aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pdf/SkPDFCatalog.cpp72
-rw-r--r--src/pdf/SkPDFStream.cpp53
-rw-r--r--src/pdf/SkPDFTypes.cpp236
-rw-r--r--src/pdf/pdf_files.mk5
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 \
+