diff options
author | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2010-09-24 22:25:30 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2010-09-24 22:25:30 +0000 |
commit | 8459d4e5e32608ec6da3f2b81731aaeb7b038843 (patch) | |
tree | 298910ded8dd42c3bd1089d1607b2ee0bd1e4cae /src/pdf/SkPDFTypes.cpp | |
parent | 3ce77e4d13372be9fbf2601498be05b8cbd4e237 (diff) |
Initial PDF backend commit: directories, build rules, primitives
This change establishes and tests the building blocks of the PDF file format.
For now, PDF code is not compiled by default.
Review URL: http://codereview.appspot.com/1950044
git-svn-id: http://skia.googlecode.com/svn/trunk@600 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf/SkPDFTypes.cpp')
-rw-r--r-- | src/pdf/SkPDFTypes.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp new file mode 100644 index 0000000000..83f133eda2 --- /dev/null +++ b/src/pdf/SkPDFTypes.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SkPDFCatalog.h" +#include "SkPDFTypes.h" +#include "SkStream.h" + +size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + SkDynamicMemoryWStream buffer; + emitObject(&buffer, catalog, indirect); + return buffer.getOffset(); +} + +void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) { + catalog->emitObjectNumber(stream, this); + stream->writeText(" obj\n"); + emitObject(stream, catalog, false); + stream->writeText("\nendobj\n"); +} + +size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) { + return catalog->getObjectNumberSize(this) + strlen(" obj\n") + + this->getOutputSize(catalog, false) + strlen("\nendobj\n"); +} + +void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + SkASSERT(!indirect); + catalog->emitObjectNumber(stream, fObj.get()); + stream->writeText(" R"); +} + +size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + SkASSERT(!indirect); + return catalog->getObjectNumberSize(fObj.get()) + strlen(" R"); +} + +void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + stream->writeDecAsText(fValue); +} + +void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + stream->writeScalarAsText(fValue); +} + +SkPDFString::SkPDFString(const char value[]) + : fValue(formatString(SkString(value))) { +} + +SkPDFString::SkPDFString(const SkString& value) + : fValue(formatString(value)) { +} + +void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + stream->write(fValue.c_str(), fValue.size()); +} + +size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + if (indirect) + return getIndirectOutputSize(catalog); + return fValue.size(); +} + +SkString SkPDFString::formatString(const SkString& input) { + SkASSERT(input.size() <= kMaxLen); + + // 7-bit clean is a heuristic to decide what string format to use; + // a 7-bit clean string should require little escaping. + bool sevenBitClean = true; + for (size_t i = 0; i < input.size(); i++) { + if (input[i] > 0x7F || input[i] < ' ') { + sevenBitClean = false; + break; + } + } + + SkString result; + if (sevenBitClean) { + result.append("("); + for (size_t i = 0; i < input.size(); i++) { + if (input[i] == '\\' || input[i] == '(' || input[i] == ')') + result.append("\\"); + result.append(input.c_str() + i, 1); + } + result.append(")"); + } else { + result.append("<"); + for (size_t i = 0; i < input.size(); i++) + result.appendHex(input[i], 2); + result.append(">"); + } + + return result; +} + +SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {} +SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {} + +void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + SkASSERT(!indirect); + stream->write(fValue.c_str(), fValue.size()); +} + +size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + SkASSERT(!indirect); + return fValue.size(); +} + +SkString SkPDFName::formatName(const SkString& input) { + SkASSERT(input.size() <= kMaxLen); + + SkString result("/"); + for (size_t i = 0; i < input.size(); i++) { + if (input[i] > 0x7F || input[i] < '!' || input[i] == '#') { + result.append("#"); + result.appendHex(input[i], 2); + } else { + result.append(input.c_str() + i, 1); + } + } + + return result; +} + +SkPDFArray::~SkPDFArray() { + fValue.safeUnrefAll(); +} + +void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + + stream->writeText("["); + for (int i = 0; i < fValue.count(); i++) { + fValue[i]->emitObject(stream, catalog, false); + if (i + 1 < fValue.count()) + stream->writeText(" "); + } + stream->writeText("]"); +} + +size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + if (indirect) + return getIndirectOutputSize(catalog); + + size_t result = strlen("[]"); + if (fValue.count()) + result += fValue.count() - 1; + for (int i = 0; i < fValue.count(); i++) + result += fValue[i]->getOutputSize(catalog, false); + return result; +} + +void SkPDFArray::reserve(int length) { + SkASSERT(length <= kMaxLen); + fValue.setReserve(length); +} + +void SkPDFArray::setAt(int offset, SkPDFObject* value) { + SkASSERT(offset < fValue.count()); + SkSafeUnref(fValue[offset]); + fValue[offset] = value; + SkSafeRef(fValue[offset]); +} + +void SkPDFArray::append(SkPDFObject* value) { + SkASSERT(fValue.count() < kMaxLen); + SkSafeRef(value); + fValue.push(value); +} + +SkPDFDict::~SkPDFDict() { + for (int i = 0; i < fValue.count(); i++) { + SkSafeUnref(fValue[i].key); + SkSafeUnref(fValue[i].value); + } +} + +void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + + stream->writeText("<<"); + for (int i = 0; i < fValue.count(); i++) { + fValue[i].key->emitObject(stream, catalog, false); + stream->writeText(" "); + fValue[i].value->emitObject(stream, catalog, false); + stream->writeText("\n"); + } + stream->writeText(">>"); +} + +size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + if (indirect) + return getIndirectOutputSize(catalog); + + size_t result = strlen("<<>>") + (fValue.count() * 2); + for (int i = 0; i < fValue.count(); i++) { + result += fValue[i].key->getOutputSize(catalog, false); + result += fValue[i].value->getOutputSize(catalog, false); + } + return result; +} + +void SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { + struct Rec* newEntry = fValue.append(); + newEntry->key = key; + SkSafeRef(newEntry->key); + newEntry->value = value; + SkSafeRef(newEntry->value); +} |