1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/pdf/SkPDFCatalog.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,215 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2010 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkPDFCatalog.h" 1.14 +#include "SkPDFTypes.h" 1.15 +#include "SkStream.h" 1.16 +#include "SkTypes.h" 1.17 + 1.18 +SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags) 1.19 + : fFirstPageCount(0), 1.20 + fNextObjNum(1), 1.21 + fNextFirstPageObjNum(0), 1.22 + fDocumentFlags(flags) { 1.23 +} 1.24 + 1.25 +SkPDFCatalog::~SkPDFCatalog() { 1.26 + fSubstituteResourcesRemaining.safeUnrefAll(); 1.27 + fSubstituteResourcesFirstPage.safeUnrefAll(); 1.28 +} 1.29 + 1.30 +SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) { 1.31 + if (findObjectIndex(obj) != -1) { // object already added 1.32 + return obj; 1.33 + } 1.34 + SkASSERT(fNextFirstPageObjNum == 0); 1.35 + if (onFirstPage) { 1.36 + fFirstPageCount++; 1.37 + } 1.38 + 1.39 + struct Rec newEntry(obj, onFirstPage); 1.40 + fCatalog.append(1, &newEntry); 1.41 + return obj; 1.42 +} 1.43 + 1.44 +size_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, off_t offset) { 1.45 + int objIndex = assignObjNum(obj) - 1; 1.46 + SkASSERT(fCatalog[objIndex].fObjNumAssigned); 1.47 + SkASSERT(fCatalog[objIndex].fFileOffset == 0); 1.48 + fCatalog[objIndex].fFileOffset = offset; 1.49 + 1.50 + return getSubstituteObject(obj)->getOutputSize(this, true); 1.51 +} 1.52 + 1.53 +void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) { 1.54 + stream->writeDecAsText(assignObjNum(obj)); 1.55 + stream->writeText(" 0"); // Generation number is always 0. 1.56 +} 1.57 + 1.58 +size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) { 1.59 + SkDynamicMemoryWStream buffer; 1.60 + emitObjectNumber(&buffer, obj); 1.61 + return buffer.getOffset(); 1.62 +} 1.63 + 1.64 +int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const { 1.65 + for (int i = 0; i < fCatalog.count(); i++) { 1.66 + if (fCatalog[i].fObject == obj) { 1.67 + return i; 1.68 + } 1.69 + } 1.70 + // If it's not in the main array, check if it's a substitute object. 1.71 + for (int i = 0; i < fSubstituteMap.count(); ++i) { 1.72 + if (fSubstituteMap[i].fSubstitute == obj) { 1.73 + return findObjectIndex(fSubstituteMap[i].fOriginal); 1.74 + } 1.75 + } 1.76 + return -1; 1.77 +} 1.78 + 1.79 +int SkPDFCatalog::assignObjNum(SkPDFObject* obj) { 1.80 + int pos = findObjectIndex(obj); 1.81 + // If this assert fails, it means you probably forgot to add an object 1.82 + // to the resource list. 1.83 + SkASSERT(pos >= 0); 1.84 + uint32_t currentIndex = pos; 1.85 + if (fCatalog[currentIndex].fObjNumAssigned) { 1.86 + return currentIndex + 1; 1.87 + } 1.88 + 1.89 + // First assignment. 1.90 + if (fNextFirstPageObjNum == 0) { 1.91 + fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1; 1.92 + } 1.93 + 1.94 + uint32_t objNum; 1.95 + if (fCatalog[currentIndex].fOnFirstPage) { 1.96 + objNum = fNextFirstPageObjNum; 1.97 + fNextFirstPageObjNum++; 1.98 + } else { 1.99 + objNum = fNextObjNum; 1.100 + fNextObjNum++; 1.101 + } 1.102 + 1.103 + // When we assign an object an object number, we put it in that array 1.104 + // offset (minus 1 because object number 0 is reserved). 1.105 + SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned); 1.106 + if (objNum - 1 != currentIndex) { 1.107 + SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]); 1.108 + } 1.109 + fCatalog[objNum - 1].fObjNumAssigned = true; 1.110 + return objNum; 1.111 +} 1.112 + 1.113 +int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) { 1.114 + int first = -1; 1.115 + int last = fCatalog.count() - 1; 1.116 + // TODO(vandebo): Support linearized format. 1.117 + // int last = fCatalog.count() - fFirstPageCount - 1; 1.118 + // if (firstPage) { 1.119 + // first = fCatalog.count() - fFirstPageCount; 1.120 + // last = fCatalog.count() - 1; 1.121 + // } 1.122 + 1.123 + stream->writeText("xref\n"); 1.124 + stream->writeDecAsText(first + 1); 1.125 + stream->writeText(" "); 1.126 + stream->writeDecAsText(last - first + 1); 1.127 + stream->writeText("\n"); 1.128 + 1.129 + if (first == -1) { 1.130 + stream->writeText("0000000000 65535 f \n"); 1.131 + first++; 1.132 + } 1.133 + for (int i = first; i <= last; i++) { 1.134 + // For 32 bits platforms, the maximum offset has to fit within off_t 1.135 + // which is a 32 bits signed integer on these platforms. 1.136 + SkDEBUGCODE(static const off_t kMaxOff = SK_MaxS32;) 1.137 + SkASSERT(fCatalog[i].fFileOffset > 0); 1.138 + SkASSERT(fCatalog[i].fFileOffset < kMaxOff); 1.139 + stream->writeBigDecAsText(fCatalog[i].fFileOffset, 10); 1.140 + stream->writeText(" 00000 n \n"); 1.141 + } 1.142 + 1.143 + return fCatalog.count() + 1; 1.144 +} 1.145 + 1.146 +void SkPDFCatalog::setSubstitute(SkPDFObject* original, 1.147 + SkPDFObject* substitute) { 1.148 +#if defined(SK_DEBUG) 1.149 + // Sanity check: is the original already in substitute list? 1.150 + for (int i = 0; i < fSubstituteMap.count(); ++i) { 1.151 + if (original == fSubstituteMap[i].fSubstitute || 1.152 + original == fSubstituteMap[i].fOriginal) { 1.153 + SkASSERT(false); 1.154 + return; 1.155 + } 1.156 + } 1.157 +#endif 1.158 + // Check if the original is on first page. 1.159 + bool onFirstPage = false; 1.160 + for (int i = 0; i < fCatalog.count(); ++i) { 1.161 + if (fCatalog[i].fObject == original) { 1.162 + onFirstPage = fCatalog[i].fOnFirstPage; 1.163 + break; 1.164 + } 1.165 +#if defined(SK_DEBUG) 1.166 + if (i == fCatalog.count() - 1) { 1.167 + SkASSERT(false); // original not in catalog 1.168 + return; 1.169 + } 1.170 +#endif 1.171 + } 1.172 + 1.173 + SubstituteMapping newMapping(original, substitute); 1.174 + fSubstituteMap.append(1, &newMapping); 1.175 + 1.176 + // Add resource objects of substitute object to catalog. 1.177 + SkTSet<SkPDFObject*>* targetSet = getSubstituteList(onFirstPage); 1.178 + SkTSet<SkPDFObject*> newResourceObjects; 1.179 + newMapping.fSubstitute->getResources(*targetSet, &newResourceObjects); 1.180 + for (int i = 0; i < newResourceObjects.count(); ++i) { 1.181 + addObject(newResourceObjects[i], onFirstPage); 1.182 + } 1.183 + // mergeInto returns the number of duplicates. 1.184 + // If there are duplicates, there is a bug and we mess ref counting. 1.185 + SkDEBUGCODE(int duplicates =) targetSet->mergeInto(newResourceObjects); 1.186 + SkASSERT(duplicates == 0); 1.187 +} 1.188 + 1.189 +SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) { 1.190 + for (int i = 0; i < fSubstituteMap.count(); ++i) { 1.191 + if (object == fSubstituteMap[i].fOriginal) { 1.192 + return fSubstituteMap[i].fSubstitute; 1.193 + } 1.194 + } 1.195 + return object; 1.196 +} 1.197 + 1.198 +off_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset, 1.199 + bool firstPage) { 1.200 + SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage); 1.201 + off_t offsetSum = fileOffset; 1.202 + for (int i = 0; i < targetSet->count(); ++i) { 1.203 + offsetSum += setFileOffset((*targetSet)[i], offsetSum); 1.204 + } 1.205 + return offsetSum - fileOffset; 1.206 +} 1.207 + 1.208 +void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) { 1.209 + SkTSet<SkPDFObject*>* targetSet = getSubstituteList(firstPage); 1.210 + for (int i = 0; i < targetSet->count(); ++i) { 1.211 + (*targetSet)[i]->emit(stream, this, true); 1.212 + } 1.213 +} 1.214 + 1.215 +SkTSet<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) { 1.216 + return firstPage ? &fSubstituteResourcesFirstPage : 1.217 + &fSubstituteResourcesRemaining; 1.218 +}