blob: c0f6fb03b9b6ad6b35fc6467d5a67b32973ecc9e [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 The Android Open Source Project
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000010#include "SkPDFCatalog.h"
11#include "SkPDFTypes.h"
12#include "SkStream.h"
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000013#include "SkTypes.h"
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000014
vandebo@chromium.org421d6442011-07-20 17:39:01 +000015SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000016 : fFirstPageCount(0),
17 fNextObjNum(1),
vandebo@chromium.org421d6442011-07-20 17:39:01 +000018 fNextFirstPageObjNum(0),
19 fDocumentFlags(flags) {
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000020}
21
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000022SkPDFCatalog::~SkPDFCatalog() {
23 fSubstituteResourcesRemaining.safeUnrefAll();
24 fSubstituteResourcesFirstPage.safeUnrefAll();
25}
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000026
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000027SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000028 if (findObjectIndex(obj) != -1) { // object already added
29 return obj;
30 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000031 SkASSERT(fNextFirstPageObjNum == 0);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000032 if (onFirstPage) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000033 fFirstPageCount++;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000034 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000035
36 struct Rec newEntry(obj, onFirstPage);
37 fCatalog.append(1, &newEntry);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000038 return obj;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000039}
40
vandebo@chromium.org30580f62012-07-12 20:22:04 +000041size_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, off_t offset) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000042 int objIndex = assignObjNum(obj) - 1;
43 SkASSERT(fCatalog[objIndex].fObjNumAssigned);
44 SkASSERT(fCatalog[objIndex].fFileOffset == 0);
45 fCatalog[objIndex].fFileOffset = offset;
46
vandebo@chromium.orgd3a094c2011-07-25 22:22:25 +000047 return getSubstituteObject(obj)->getOutputSize(this, true);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000048}
49
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000050void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) {
51 stream->writeDecAsText(assignObjNum(obj));
52 stream->writeText(" 0"); // Generation number is always 0.
53}
54
55size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) {
56 SkDynamicMemoryWStream buffer;
57 emitObjectNumber(&buffer, obj);
58 return buffer.getOffset();
59}
60
61int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
62 for (int i = 0; i < fCatalog.count(); i++) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000063 if (fCatalog[i].fObject == obj) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000064 return i;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000065 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000066 }
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000067 // If it's not in the main array, check if it's a substitute object.
68 for (int i = 0; i < fSubstituteMap.count(); ++i) {
69 if (fSubstituteMap[i].fSubstitute == obj) {
70 return findObjectIndex(fSubstituteMap[i].fOriginal);
71 }
72 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000073 return -1;
74}
75
76int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
77 int pos = findObjectIndex(obj);
vandebo@chromium.orgda912d62011-03-08 18:31:02 +000078 // If this assert fails, it means you probably forgot to add an object
79 // to the resource list.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000080 SkASSERT(pos >= 0);
81 uint32_t currentIndex = pos;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000082 if (fCatalog[currentIndex].fObjNumAssigned) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000083 return currentIndex + 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000084 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000085
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000086 // First assignment.
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000087 if (fNextFirstPageObjNum == 0) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000088 fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000089 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000090
91 uint32_t objNum;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000092 if (fCatalog[currentIndex].fOnFirstPage) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000093 objNum = fNextFirstPageObjNum;
94 fNextFirstPageObjNum++;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000095 } else {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000096 objNum = fNextObjNum;
97 fNextObjNum++;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000098 }
99
100 // When we assign an object an object number, we put it in that array
101 // offset (minus 1 because object number 0 is reserved).
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000102 SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000103 if (objNum - 1 != currentIndex) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000104 SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000105 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000106 fCatalog[objNum - 1].fObjNumAssigned = true;
107 return objNum;
108}
109
110int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) {
111 int first = -1;
112 int last = fCatalog.count() - 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000113 // TODO(vandebo): Support linearized format.
ctguil@chromium.orga5c72342011-08-15 23:55:03 +0000114 // int last = fCatalog.count() - fFirstPageCount - 1;
115 // if (firstPage) {
116 // first = fCatalog.count() - fFirstPageCount;
117 // last = fCatalog.count() - 1;
118 // }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000119
120 stream->writeText("xref\n");
121 stream->writeDecAsText(first + 1);
122 stream->writeText(" ");
123 stream->writeDecAsText(last - first + 1);
124 stream->writeText("\n");
125
126 if (first == -1) {
127 stream->writeText("0000000000 65535 f \n");
128 first++;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000129 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000130 for (int i = first; i <= last; i++) {
131 SkASSERT(fCatalog[i].fFileOffset > 0);
132 SkASSERT(fCatalog[i].fFileOffset <= 9999999999LL);
133 stream->writeBigDecAsText(fCatalog[i].fFileOffset, 10);
134 stream->writeText(" 00000 n \n");
135 }
136
137 return fCatalog.count() + 1;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000138}
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000139
140void SkPDFCatalog::setSubstitute(SkPDFObject* original,
141 SkPDFObject* substitute) {
142#if defined(SK_DEBUG)
143 // Sanity check: is the original already in substitute list?
144 for (int i = 0; i < fSubstituteMap.count(); ++i) {
145 if (original == fSubstituteMap[i].fSubstitute ||
146 original == fSubstituteMap[i].fOriginal) {
147 SkASSERT(false);
148 return;
149 }
150 }
151#endif
152 // Check if the original is on first page.
153 bool onFirstPage = false;
154 for (int i = 0; i < fCatalog.count(); ++i) {
155 if (fCatalog[i].fObject == original) {
156 onFirstPage = fCatalog[i].fOnFirstPage;
157 break;
158 }
159#if defined(SK_DEBUG)
160 if (i == fCatalog.count() - 1) {
161 SkASSERT(false); // original not in catalog
162 return;
163 }
164#endif
165 }
166
167 SubstituteMapping newMapping(original, substitute);
168 fSubstituteMap.append(1, &newMapping);
169
170 // Add resource objects of substitute object to catalog.
edisonn@google.com5bd26d32013-02-28 14:01:44 +0000171 SkTDArray<SkPDFObject*>* targetList = getSubstituteList(onFirstPage);
172 int existingSize = targetList->count();
173 newMapping.fSubstitute->getResources(targetList);
174 for (int i = existingSize; i < targetList->count(); ++i) {
175 addObject((*targetList)[i], onFirstPage);
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000176 }
177}
178
179SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
180 for (int i = 0; i < fSubstituteMap.count(); ++i) {
181 if (object == fSubstituteMap[i].fOriginal) {
182 return fSubstituteMap[i].fSubstitute;
183 }
184 }
185 return object;
186}
187
188off_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset,
189 bool firstPage) {
edisonn@google.com5bd26d32013-02-28 14:01:44 +0000190 SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000191 off_t offsetSum = fileOffset;
edisonn@google.com5bd26d32013-02-28 14:01:44 +0000192 for (int i = 0; i < targetList->count(); ++i) {
193 offsetSum += setFileOffset((*targetList)[i], offsetSum);
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000194 }
vandebo@chromium.orgf5181a42011-07-20 00:33:53 +0000195 return offsetSum - fileOffset;
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000196}
197
198void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) {
edisonn@google.com5bd26d32013-02-28 14:01:44 +0000199 SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
200 for (int i = 0; i < targetList->count(); ++i) {
201 (*targetList)[i]->emit(stream, this, true);
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000202 }
203}
204
edisonn@google.com5bd26d32013-02-28 14:01:44 +0000205SkTDArray<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000206 return firstPage ? &fSubstituteResourcesFirstPage :
207 &fSubstituteResourcesRemaining;
vandebo@chromium.orgf5181a42011-07-20 00:33:53 +0000208}