aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf/SkPDFCatalog.h
blob: c7c6d6e2995652f0c0c8260381bbfe4d1feaaf15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

/*
 * Copyright 2010 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#ifndef SkPDFCatalog_DEFINED
#define SkPDFCatalog_DEFINED

#include <sys/types.h>

#include "SkPDFDocument.h"
#include "SkPDFTypes.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"

/** \class SkPDFCatalog

    The PDF catalog manages object numbers and file offsets.  It is used
    to create the PDF cross reference table.
*/
class SkPDFCatalog {
public:
    /** Create a PDF catalog.
     */
    explicit SkPDFCatalog(SkPDFDocument::Flags flags);
    ~SkPDFCatalog();

    /** Add the passed object to the catalog.  Refs obj.
     *  @param obj         The object to add.
     *  @param onFirstPage Is the object on the first page.
     *  @return The obj argument is returned.
     */
    SkPDFObject* addObject(SkPDFObject* obj, bool onFirstPage);

    /** Inform the catalog of the object's position in the final stream.
     *  The object should already have been added to the catalog.  Returns
     *  the object's size.
     *  @param obj         The object to add.
     *  @param offset      The byte offset in the output stream of this object.
     */
    size_t setFileOffset(SkPDFObject* obj, off_t offset);

    /** Output the object number for the passed object.
     *  @param obj         The object of interest.
     *  @param stream      The writable output stream to send the output to.
     */
    void emitObjectNumber(SkWStream* stream, SkPDFObject* obj);

    /** Return the number of bytes that would be emitted for the passed
     *  object's object number.
     *  @param obj         The object of interest
     */
    size_t getObjectNumberSize(SkPDFObject* obj);

    /** Return the document flags in effect for this catalog/document.
     */
    SkPDFDocument::Flags getDocumentFlags() const { return fDocumentFlags; }

    /** Output the cross reference table for objects in the catalog.
     *  Returns the total number of objects.
     *  @param stream      The writable output stream to send the output to.
     *  @param firstPage   If true, include first page objects only, otherwise
     *                     include all objects not on the first page.
     */
    int32_t emitXrefTable(SkWStream* stream, bool firstPage);

    /** Set substitute object for the passed object.
     */
    void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);

    /** Find and return any substitute object set for the passed object. If
     *  there is none, return the passed object.
     */
    SkPDFObject* getSubstituteObject(SkPDFObject* object);

    /** Set file offsets for the resources of substitute objects.
     *  @param fileOffset Accumulated offset of current document.
     *  @param firstPage  Indicate whether this is for the first page only.
     *  @return           Total size of resources of substitute objects.
     */
    off_t setSubstituteResourcesOffsets(off_t fileOffset, bool firstPage);

    /** Emit the resources of substitute objects.
     */
    void emitSubstituteResources(SkWStream* stream, bool firstPage);

private:
    struct Rec {
        Rec(SkPDFObject* object, bool onFirstPage)
            : fObject(object),
              fFileOffset(0),
              fObjNumAssigned(false),
              fOnFirstPage(onFirstPage) {
        }
        SkPDFObject* fObject;
        off_t fFileOffset;
        bool fObjNumAssigned;
        bool fOnFirstPage;
    };

    struct SubstituteMapping {
        SubstituteMapping(SkPDFObject* original, SkPDFObject* substitute)
            : fOriginal(original), fSubstitute(substitute) {
        }
        SkPDFObject* fOriginal;
        SkPDFObject* fSubstitute;
    };

    // TODO(vandebo): Make this a hash if it's a performance problem.
    SkTDArray<struct Rec> fCatalog;

    // TODO(arthurhsu): Make this a hash if it's a performance problem.
    SkTDArray<SubstituteMapping> fSubstituteMap;
    SkTSet<SkPDFObject*> fSubstituteResourcesFirstPage;
    SkTSet<SkPDFObject*> fSubstituteResourcesRemaining;

    // Number of objects on the first page.
    uint32_t fFirstPageCount;
    // Next object number to assign (on page > 1).
    uint32_t fNextObjNum;
    // Next object number to assign on the first page.
    uint32_t fNextFirstPageObjNum;

    SkPDFDocument::Flags fDocumentFlags;

    int findObjectIndex(SkPDFObject* obj) const;

    int assignObjNum(SkPDFObject* obj);

    SkTSet<SkPDFObject*>* getSubstituteList(bool firstPage);
};

#endif