blob: 201d62b2efe05465f7ee36be6357fbb27a2d5b30 [file] [log] [blame]
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 The Android Open Source Project
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00006 */
7
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00009#ifndef SkPDFTypes_DEFINED
10#define SkPDFTypes_DEFINED
11
12#include "SkRefCnt.h"
13#include "SkScalar.h"
halcanary37c46ca2015-03-31 12:30:20 -070014#include "SkTHash.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000015#include "SkTypes.h"
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000016
halcanaryfa251062016-07-29 10:13:18 -070017class SkData;
halcanary37c46ca2015-03-31 12:30:20 -070018class SkPDFObjNumMap;
halcanarybf799cd2015-02-10 13:32:09 -080019class SkPDFObject;
martina.kollarovab8d6af12016-06-29 05:12:31 -070020class SkStreamAsset;
21class SkString;
22class SkWStream;
halcanarybf799cd2015-02-10 13:32:09 -080023
halcanary7a14b312015-10-01 07:28:13 -070024#ifdef SK_PDF_IMAGE_STATS
25#include "SkAtomics.h"
26#endif
27
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000028/** \class SkPDFObject
29
30 A PDF Object is the base class for primitive elements in a PDF file. A
31 common subtype is used to ease the use of indirect object references,
32 which are common in the PDF format.
halcanary130444f2015-04-25 06:45:07 -070033
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000034*/
35class SkPDFObject : public SkRefCnt {
36public:
halcanary6a144342015-01-23 11:45:10 -080037 /** Subclasses must implement this method to print the object to the
38 * PDF file.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000039 * @param catalog The object catalog to use.
halcanary6a144342015-01-23 11:45:10 -080040 * @param stream The writable output stream to send the output to.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000041 */
halcanary37c46ca2015-03-31 12:30:20 -070042 virtual void emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -070043 const SkPDFObjNumMap& objNumMap) const = 0;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000044
halcanarybf799cd2015-02-10 13:32:09 -080045 /**
halcanaryd4714af2015-03-25 13:23:13 -070046 * Adds all transitive dependencies of this object to the
47 * catalog. Implementations should respect the catalog's object
48 * substitution map.
vandebo@chromium.orga5180862010-10-26 19:48:49 +000049 */
halcanary530032a2016-08-18 14:22:52 -070050 virtual void addResources(SkPDFObjNumMap* catalog) const {}
vandebo@chromium.org421d6442011-07-20 17:39:01 +000051
halcanarybae235e2016-03-21 10:05:23 -070052 /**
53 * Release all resources associated with this SkPDFObject. It is
54 * an error to call emitObject() or addResources() after calling
55 * drop().
56 */
57 virtual void drop() {}
58
59 virtual ~SkPDFObject() {}
halcanary6a144342015-01-23 11:45:10 -080060private:
halcanary4fc48af2015-01-12 10:07:50 -080061 typedef SkRefCnt INHERITED;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000062};
63
halcanary130444f2015-04-25 06:45:07 -070064////////////////////////////////////////////////////////////////////////////////
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000065
halcanary130444f2015-04-25 06:45:07 -070066/**
67 A SkPDFUnion is a non-virtualized implementation of the
68 non-compound, non-specialized PDF Object types: Name, String,
69 Number, Boolean.
70 */
71class SkPDFUnion {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000072public:
halcanary130444f2015-04-25 06:45:07 -070073 // Move contstructor and assignemnt operator destroy the argument
74 // and steal their references (if needed).
75 SkPDFUnion(SkPDFUnion&& other);
76 SkPDFUnion& operator=(SkPDFUnion&& other);
reed@google.com3b429982012-06-26 15:30:08 +000077
halcanary130444f2015-04-25 06:45:07 -070078 ~SkPDFUnion();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000079
halcanary130444f2015-04-25 06:45:07 -070080 /** The following nine functions are the standard way of creating
81 SkPDFUnion objects. */
82
83 static SkPDFUnion Int(int32_t);
84
halcanary725c6202015-08-20 08:09:37 -070085 static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); }
halcanaryf7a169e2015-05-01 07:35:45 -070086
halcanary130444f2015-04-25 06:45:07 -070087 static SkPDFUnion Bool(bool);
88
89 static SkPDFUnion Scalar(SkScalar);
90
halcanaryeb92cb32016-07-15 13:41:27 -070091 static SkPDFUnion ColorComponent(uint8_t);
92
halcanary8103a342016-03-08 15:10:16 -080093 /** These two functions do NOT take ownership of char*, and do NOT
halcanary130444f2015-04-25 06:45:07 -070094 copy the string. Suitable for passing in static const
95 strings. For example:
96 SkPDFUnion n = SkPDFUnion::Name("Length");
97 SkPDFUnion u = SkPDFUnion::String("Identity"); */
98
99 /** SkPDFUnion::Name(const char*) assumes that the passed string
100 is already a valid name (that is: it has no control or
101 whitespace characters). This will not copy the name. */
102 static SkPDFUnion Name(const char*);
103
104 /** SkPDFUnion::String will encode the passed string. This will
105 not copy the name. */
106 static SkPDFUnion String(const char*);
107
108 /** SkPDFUnion::Name(const SkString&) does not assume that the
109 passed string is already a valid name and it will escape the
110 string. */
111 static SkPDFUnion Name(const SkString&);
112
113 /** SkPDFUnion::String will encode the passed string. */
114 static SkPDFUnion String(const SkString&);
115
halcanary8103a342016-03-08 15:10:16 -0800116 static SkPDFUnion Object(sk_sp<SkPDFObject>);
117 static SkPDFUnion ObjRef(sk_sp<SkPDFObject>);
halcanary130444f2015-04-25 06:45:07 -0700118
119 /** These two non-virtual methods mirror SkPDFObject's
120 corresponding virtuals. */
halcanary530032a2016-08-18 14:22:52 -0700121 void emitObject(SkWStream*, const SkPDFObjNumMap&) const;
122 void addResources(SkPDFObjNumMap*) const;
halcanary130444f2015-04-25 06:45:07 -0700123
124 bool isName() const;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000125
126private:
halcanary130444f2015-04-25 06:45:07 -0700127 union {
128 int32_t fIntValue;
129 bool fBoolValue;
130 SkScalar fScalarValue;
131 const char* fStaticString;
132 char fSkString[sizeof(SkString)];
133 SkPDFObject* fObject;
134 };
135 enum class Type : char {
136 /** It is an error to call emitObject() or addResources() on an
137 kDestroyed object. */
138 kDestroyed = 0,
139 kInt,
halcanaryeb92cb32016-07-15 13:41:27 -0700140 kColorComponent,
halcanary130444f2015-04-25 06:45:07 -0700141 kBool,
142 kScalar,
143 kName,
144 kString,
145 kNameSkS,
146 kStringSkS,
147 kObjRef,
148 kObject,
149 };
150 Type fType;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000151
halcanary130444f2015-04-25 06:45:07 -0700152 SkPDFUnion(Type);
153 // We do not now need copy constructor and copy assignment, so we
154 // will disable this functionality.
155 SkPDFUnion& operator=(const SkPDFUnion&) = delete;
156 SkPDFUnion(const SkPDFUnion&) = delete;
157};
bungeman99fe8222015-08-20 07:57:51 -0700158static_assert(sizeof(SkString) == sizeof(void*), "SkString_size");
halcanary130444f2015-04-25 06:45:07 -0700159
160////////////////////////////////////////////////////////////////////////////////
161
halcanary002653e2015-05-05 11:28:55 -0700162#if 0 // Enable if needed.
163/** This class is a SkPDFUnion with SkPDFObject virtuals attached.
164 The only use case of this is when a non-compound PDF object is
165 referenced indirectly. */
halcanary70d15542015-11-22 12:55:04 -0800166class SkPDFAtom final : public SkPDFObject {
halcanary130444f2015-04-25 06:45:07 -0700167public:
168 void emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700169 const SkPDFObjNumMap& objNumMap) final;
170 void addResources(SkPDFObjNumMap* const final;
halcanary8103a342016-03-08 15:10:16 -0800171 SkPDFAtom(SkPDFUnion&& v) : fValue(std::move(v) {}
halcanary130444f2015-04-25 06:45:07 -0700172
173private:
174 const SkPDFUnion fValue;
reed@google.com3b429982012-06-26 15:30:08 +0000175 typedef SkPDFObject INHERITED;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000176};
halcanary002653e2015-05-05 11:28:55 -0700177#endif // 0
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000178
halcanarybc4696b2015-05-06 10:56:04 -0700179////////////////////////////////////////////////////////////////////////////////
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000180
181/** \class SkPDFArray
182
183 An array object in a PDF.
184*/
halcanary70d15542015-11-22 12:55:04 -0800185class SkPDFArray final : public SkPDFObject {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000186public:
187 /** Create a PDF array. Maximum length is 8191.
188 */
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000189 SkPDFArray();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000190 virtual ~SkPDFArray();
191
192 // The SkPDFObject interface.
tfarinaf4219dd2015-04-27 17:18:28 -0700193 void emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700194 const SkPDFObjNumMap& objNumMap) const override;
195 void addResources(SkPDFObjNumMap*) const override;
halcanarybae235e2016-03-21 10:05:23 -0700196 void drop() override;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000197
198 /** The size of the array.
199 */
halcanary130444f2015-04-25 06:45:07 -0700200 int size() const;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000201
202 /** Preallocate space for the given number of entries.
203 * @param length The number of array slots to preallocate.
204 */
205 void reserve(int length);
206
halcanary130444f2015-04-25 06:45:07 -0700207 /** Appends a value to the end of the array.
reed@google.comc789cf12011-07-20 12:14:33 +0000208 * @param value The value to add to the array.
209 */
halcanary130444f2015-04-25 06:45:07 -0700210 void appendInt(int32_t);
halcanaryeb92cb32016-07-15 13:41:27 -0700211 void appendColorComponent(uint8_t);
halcanary130444f2015-04-25 06:45:07 -0700212 void appendBool(bool);
213 void appendScalar(SkScalar);
214 void appendName(const char[]);
215 void appendName(const SkString&);
216 void appendString(const char[]);
217 void appendString(const SkString&);
halcanary8103a342016-03-08 15:10:16 -0800218 void appendObject(sk_sp<SkPDFObject>);
219 void appendObjRef(sk_sp<SkPDFObject>);
ctguil@chromium.orga5c72342011-08-15 23:55:03 +0000220
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000221private:
halcanarybae235e2016-03-21 10:05:23 -0700222 SkTArray<SkPDFUnion> fValues;
halcanary130444f2015-04-25 06:45:07 -0700223 void append(SkPDFUnion&& value);
halcanarybae235e2016-03-21 10:05:23 -0700224 SkDEBUGCODE(bool fDumped;)
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000225};
226
227/** \class SkPDFDict
228
229 A dictionary object in a PDF.
230*/
231class SkPDFDict : public SkPDFObject {
232public:
halcanarybae235e2016-03-21 10:05:23 -0700233 /** Create a PDF dictionary.
234 * @param type The value of the Type entry, nullptr for no type.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000235 */
halcanarybae235e2016-03-21 10:05:23 -0700236 explicit SkPDFDict(const char type[] = nullptr);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000237
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000238 virtual ~SkPDFDict();
239
240 // The SkPDFObject interface.
tfarinaf4219dd2015-04-27 17:18:28 -0700241 void emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700242 const SkPDFObjNumMap& objNumMap) const override;
243 void addResources(SkPDFObjNumMap*) const override;
halcanarybae235e2016-03-21 10:05:23 -0700244 void drop() override;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000245
246 /** The size of the dictionary.
247 */
halcanary1f8ed022014-06-27 10:37:27 -0700248 int size() const;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000249
halcanary8103a342016-03-08 15:10:16 -0800250 /** Add the value to the dictionary with the given key.
reed@google.comc789cf12011-07-20 12:14:33 +0000251 * @param key The text of the key for this dictionary entry.
halcanary130444f2015-04-25 06:45:07 -0700252 * @param value The value for this dictionary entry.
253 */
halcanary8103a342016-03-08 15:10:16 -0800254 void insertObject(const char key[], sk_sp<SkPDFObject>);
255 void insertObject(const SkString& key, sk_sp<SkPDFObject>);
256 void insertObjRef(const char key[], sk_sp<SkPDFObject>);
257 void insertObjRef(const SkString& key, sk_sp<SkPDFObject>);
halcanary130444f2015-04-25 06:45:07 -0700258
259 /** Add the value to the dictionary with the given key.
260 * @param key The text of the key for this dictionary entry.
261 * @param value The value for this dictionary entry.
reed@google.comc789cf12011-07-20 12:14:33 +0000262 */
halcanarya25b3372015-04-27 14:00:09 -0700263 void insertBool(const char key[], bool value);
reed@google.comc789cf12011-07-20 12:14:33 +0000264 void insertInt(const char key[], int32_t value);
halcanary130444f2015-04-25 06:45:07 -0700265 void insertInt(const char key[], size_t value);
reed@google.comc789cf12011-07-20 12:14:33 +0000266 void insertScalar(const char key[], SkScalar value);
halcanary130444f2015-04-25 06:45:07 -0700267 void insertName(const char key[], const char nameValue[]);
268 void insertName(const char key[], const SkString& nameValue);
269 void insertString(const char key[], const char value[]);
270 void insertString(const char key[], const SkString& value);
ctguil@chromium.orga5c72342011-08-15 23:55:03 +0000271
halcanary725c6202015-08-20 08:09:37 -0700272 /** Emit the dictionary, without the "<<" and ">>".
273 */
274 void emitAll(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700275 const SkPDFObjNumMap& objNumMap) const;
halcanary725c6202015-08-20 08:09:37 -0700276
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000277private:
halcanary130444f2015-04-25 06:45:07 -0700278 struct Record {
279 SkPDFUnion fKey;
280 SkPDFUnion fValue;
halcanarybae235e2016-03-21 10:05:23 -0700281 Record(SkPDFUnion&&, SkPDFUnion&&);
halcanary9be37202016-08-08 07:21:42 -0700282 Record(Record&&) = default;
283 Record& operator=(Record&&) = default;
halcanarybae235e2016-03-21 10:05:23 -0700284 Record(const Record&) = delete;
285 Record& operator=(const Record&) = delete;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000286 };
halcanarybae235e2016-03-21 10:05:23 -0700287 SkTArray<Record> fRecords;
288 SkDEBUGCODE(bool fDumped;)
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000289};
290
halcanary725c6202015-08-20 08:09:37 -0700291/** \class SkPDFSharedStream
292
293 This class takes an asset and assumes that it is backed by
294 long-lived shared data (for example, an open file
295 descriptor). That is: no memory savings can be made by holding on
296 to a compressed version instead.
297 */
halcanary70d15542015-11-22 12:55:04 -0800298class SkPDFSharedStream final : public SkPDFObject {
halcanary725c6202015-08-20 08:09:37 -0700299public:
halcanaryfa251062016-07-29 10:13:18 -0700300 SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
halcanarybae235e2016-03-21 10:05:23 -0700301 ~SkPDFSharedStream();
halcanaryfa251062016-07-29 10:13:18 -0700302 SkPDFDict* dict() { return &fDict; }
halcanary725c6202015-08-20 08:09:37 -0700303 void emitObject(SkWStream*,
halcanary530032a2016-08-18 14:22:52 -0700304 const SkPDFObjNumMap&) const override;
305 void addResources(SkPDFObjNumMap*) const override;
halcanarybae235e2016-03-21 10:05:23 -0700306 void drop() override;
halcanary725c6202015-08-20 08:09:37 -0700307
308private:
halcanaryb8fb9932016-03-28 07:58:30 -0700309 std::unique_ptr<SkStreamAsset> fAsset;
halcanaryfa251062016-07-29 10:13:18 -0700310 SkPDFDict fDict;
halcanary725c6202015-08-20 08:09:37 -0700311 typedef SkPDFObject INHERITED;
312};
313
halcanaryfa251062016-07-29 10:13:18 -0700314/** \class SkPDFStream
315
316 This class takes an asset and assumes that it is the only owner of
317 the asset's data. It immediately compresses the asset to save
318 memory.
319 */
320
halcanarydabd4f02016-08-03 11:16:56 -0700321class SkPDFStream final : public SkPDFObject {
halcanaryfa251062016-07-29 10:13:18 -0700322
323public:
324 /** Create a PDF stream. A Length entry is automatically added to the
325 * stream dictionary.
326 * @param data The data part of the stream.
327 * @param stream The data part of the stream. */
328 explicit SkPDFStream(sk_sp<SkData> data);
329 explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream);
330 virtual ~SkPDFStream();
331
332 SkPDFDict* dict() { return &fDict; }
333
334 // The SkPDFObject interface.
335 void emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700336 const SkPDFObjNumMap& objNumMap) const override;
337 void addResources(SkPDFObjNumMap*) const final;
halcanaryfa251062016-07-29 10:13:18 -0700338 void drop() override;
339
340protected:
341 /* Create a PDF stream with no data. The setData method must be called to
342 * set the data. */
343 SkPDFStream();
344
345 /** Only call this function once. */
346 void setData(std::unique_ptr<SkStreamAsset> stream);
347
348private:
349 std::unique_ptr<SkStreamAsset> fCompressedData;
350 SkPDFDict fDict;
351
352 typedef SkPDFDict INHERITED;
353};
354
halcanary37c46ca2015-03-31 12:30:20 -0700355////////////////////////////////////////////////////////////////////////////////
356
halcanary37c46ca2015-03-31 12:30:20 -0700357/** \class SkPDFObjNumMap
358
359 The PDF Object Number Map manages object numbers. It is used to
360 create the PDF cross reference table.
361*/
362class SkPDFObjNumMap : SkNoncopyable {
363public:
364 /** Add the passed object to the catalog.
365 * @param obj The object to add.
366 * @return True iff the object was not already added to the catalog.
367 */
368 bool addObject(SkPDFObject* obj);
369
halcanary34422612015-10-12 10:11:18 -0700370 /** Add the passed object to the catalog, as well as all its dependencies.
371 * @param obj The object to add. If nullptr, this is a noop.
halcanary34422612015-10-12 10:11:18 -0700372 */
halcanary530032a2016-08-18 14:22:52 -0700373 void addObjectRecursively(SkPDFObject* obj);
halcanary34422612015-10-12 10:11:18 -0700374
halcanary37c46ca2015-03-31 12:30:20 -0700375 /** Get the object number for the passed object.
376 * @param obj The object of interest.
377 */
378 int32_t getObjectNumber(SkPDFObject* obj) const;
379
halcanarybae235e2016-03-21 10:05:23 -0700380 const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; }
halcanary37c46ca2015-03-31 12:30:20 -0700381
382private:
halcanarybae235e2016-03-21 10:05:23 -0700383 SkTArray<sk_sp<SkPDFObject>> fObjects;
halcanary37c46ca2015-03-31 12:30:20 -0700384 SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
385};
386
halcanary130444f2015-04-25 06:45:07 -0700387////////////////////////////////////////////////////////////////////////////////
388
halcanary7a14b312015-10-01 07:28:13 -0700389#ifdef SK_PDF_IMAGE_STATS
390extern SkAtomic<int> gDrawImageCalls;
391extern SkAtomic<int> gJpegImageObjects;
392extern SkAtomic<int> gRegularImageObjects;
393extern void SkPDFImageDumpStats();
394#endif // SK_PDF_IMAGE_STATS
395
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000396#endif