1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "SkPDFCatalog.h" 18 #include "SkPDFTypes.h" 19 #include "SkStream.h" 20 #include "SkTypes.h" 21 22 SkPDFCatalog::SkPDFCatalog() 23 : fFirstPageCount(0), 24 fNextObjNum(1), 25 fNextFirstPageObjNum(0) { 26 } 27 28 SkPDFCatalog::~SkPDFCatalog() {} 29 30 SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) { 31 SkASSERT(findObjectIndex(obj) == -1); 32 SkASSERT(fNextFirstPageObjNum == 0); 33 if (onFirstPage) 34 fFirstPageCount++; 35 36 struct Rec newEntry(obj, onFirstPage); 37 fCatalog.append(1, &newEntry); 38 return obj; 39 } 40 41 size_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, size_t offset) { 42 int objIndex = assignObjNum(obj) - 1; 43 SkASSERT(fCatalog[objIndex].fObjNumAssigned); 44 SkASSERT(fCatalog[objIndex].fFileOffset == 0); 45 fCatalog[objIndex].fFileOffset = offset; 46 47 return obj->getOutputSize(this, true); 48 } 49 50 void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) { 51 stream->writeDecAsText(assignObjNum(obj)); 52 stream->writeText(" 0"); // Generation number is always 0. 53 } 54 55 size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) { 56 SkDynamicMemoryWStream buffer; 57 emitObjectNumber(&buffer, obj); 58 return buffer.getOffset(); 59 } 60 61 int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const { 62 for (int i = 0; i < fCatalog.count(); i++) { 63 if (fCatalog[i].fObject == obj) 64 return i; 65 } 66 return -1; 67 } 68 69 int SkPDFCatalog::assignObjNum(SkPDFObject* obj) { 70 int pos = findObjectIndex(obj); 71 // If this assert fails, it means you probably forgot to add an object 72 // to the resource list. 73 SkASSERT(pos >= 0); 74 uint32_t currentIndex = pos; 75 if (fCatalog[currentIndex].fObjNumAssigned) 76 return currentIndex + 1; 77 78 // First assignment. 79 if (fNextFirstPageObjNum == 0) 80 fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1; 81 82 uint32_t objNum; 83 if (fCatalog[currentIndex].fOnFirstPage) { 84 objNum = fNextFirstPageObjNum; 85 fNextFirstPageObjNum++; 86 } else { 87 objNum = fNextObjNum; 88 fNextObjNum++; 89 } 90 91 // When we assign an object an object number, we put it in that array 92 // offset (minus 1 because object number 0 is reserved). 93 SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned); 94 if (objNum - 1 != currentIndex) 95 SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]); 96 fCatalog[objNum - 1].fObjNumAssigned = true; 97 return objNum; 98 } 99 100 int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) { 101 int first = -1; 102 int last = fCatalog.count() - 1; 103 // TODO(vandebo) support linearized format. 104 //int last = fCatalog.count() - fFirstPageCount - 1; 105 //if (firstPage) { 106 // first = fCatalog.count() - fFirstPageCount; 107 // last = fCatalog.count() - 1; 108 //} 109 110 stream->writeText("xref\n"); 111 stream->writeDecAsText(first + 1); 112 stream->writeText(" "); 113 stream->writeDecAsText(last - first + 1); 114 stream->writeText("\n"); 115 116 if (first == -1) { 117 stream->writeText("0000000000 65535 f \n"); 118 first++; 119 } 120 for (int i = first; i <= last; i++) { 121 SkASSERT(fCatalog[i].fFileOffset > 0); 122 SkASSERT(fCatalog[i].fFileOffset <= 9999999999LL); 123 stream->writeBigDecAsText(fCatalog[i].fFileOffset, 10); 124 stream->writeText(" 00000 n \n"); 125 } 126 127 return fCatalog.count() + 1; 128 } 129