Home | History | Annotate | Download | only in pdf
      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