diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/pdf/SkPDFCatalog.cpp | 72 | ||||
-rw-r--r-- | src/pdf/SkPDFStream.cpp | 53 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.cpp | 236 | ||||
-rw-r--r-- | src/pdf/pdf_files.mk | 5 |
4 files changed, 366 insertions, 0 deletions
diff --git a/src/pdf/SkPDFCatalog.cpp b/src/pdf/SkPDFCatalog.cpp new file mode 100644 index 0000000000..dd3cd7eab6 --- /dev/null +++ b/src/pdf/SkPDFCatalog.cpp @@ -0,0 +1,72 @@ +/* + * 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" + +void SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) { + SkASSERT(findObjectIndex(obj) == -1); + SkASSERT(!fStartedAssigningObjNums); + + struct Rec newEntry(obj, onFirstPage); + fCatalog.append(1, &newEntry); +} + +void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) { + stream->writeDecAsText(assignObjNum(obj)); + stream->writeText(" 0"); // Generation number is always 0. +} + +size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) { + SkDynamicMemoryWStream buffer; + emitObjectNumber(&buffer, obj); + return buffer.getOffset(); +} + +int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const { + for (int i = 0; i < fCatalog.count(); i++) { + if (fCatalog[i].fObject == obj) + return i; + } + return -1; +} + +int SkPDFCatalog::assignObjNum(SkPDFObject* obj) { + int pos = findObjectIndex(obj); + SkASSERT(pos >= 0); + uint32_t currentIndex = pos; + if (fCatalog[currentIndex].fObjNumAssigned) + return currentIndex + 1; + + fStartedAssigningObjNums = true; + if (fCatalog[currentIndex].fOnFirstPage) { + fAssigningFirstPageObjNums = true; + } else { + SkASSERT(!fAssigningFirstPageObjNums); + } + + // When we assign an object an object number, we put it in that array + // offset (minus 1 because object number 0 is reserved). + if (fNextObjNum - 1 != currentIndex) { + Rec other = fCatalog[fNextObjNum - 1]; + fCatalog[fNextObjNum - 1] = fCatalog[currentIndex]; + fCatalog[currentIndex] = other; + } + fCatalog[fNextObjNum - 1].fObjNumAssigned = true; + fNextObjNum++; + return fNextObjNum - 1; +} diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp new file mode 100644 index 0000000000..a7fbc62521 --- /dev/null +++ b/src/pdf/SkPDFStream.cpp @@ -0,0 +1,53 @@ +/* + * 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 "SkPDFStream.h" +#include "SkStream.h" + +SkPDFStream::SkPDFStream(SkStream* stream) : fData(stream) { + SkRefPtr<SkPDFName> lenKey = new SkPDFName("Length"); + lenKey->unref(); // SkRefPtr and new both took a reference. + SkRefPtr<SkPDFInt> lenValue = new SkPDFInt(fData->read(NULL, 0)); + lenValue->unref(); // SkRefPtr and new both took a reference. + fDict.insert(lenKey.get(), lenValue.get()); +} + +SkPDFStream::~SkPDFStream() { +} + +void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) { + if (indirect) + return emitIndirectObject(stream, catalog); + + fDict.emitObject(stream, catalog, false); + stream->writeText(" stream\n"); + stream->write(fData->getMemoryBase(), fData->read(NULL, 0)); + stream->writeText("endstream\n"); +} + +size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) { + if (indirect) + return getIndirectOutputSize(catalog); + + return fDict.getOutputSize(catalog, false) + + strlen(" stream\nendstream\n") + fData->read(NULL, 0); +} + +void SkPDFStream::insert(SkPDFName* key, SkPDFObject* value) { + fDict.insert(key, value); +} 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); +} diff --git a/src/pdf/pdf_files.mk b/src/pdf/pdf_files.mk new file mode 100644 index 0000000000..5e41eeacdb --- /dev/null +++ b/src/pdf/pdf_files.mk @@ -0,0 +1,5 @@ +SOURCE := \ + SkPDFCatalog.cpp \ + SkPDFStream.cpp \ + SkPDFTypes.cpp \ + |