1 /* 2 * Copyright 2010 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 #ifndef SkPDFTypes_DEFINED 10 #define SkPDFTypes_DEFINED 11 12 #include "SkRefCnt.h" 13 #include "SkScalar.h" 14 #include "SkTHash.h" 15 #include "SkTypes.h" 16 17 class SkData; 18 class SkPDFObjNumMap; 19 class SkPDFObject; 20 class SkStreamAsset; 21 class SkString; 22 class SkWStream; 23 24 #ifdef SK_PDF_IMAGE_STATS 25 #include "SkAtomics.h" 26 #endif 27 28 /** \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. 33 34 */ 35 class SkPDFObject : public SkRefCnt { 36 public: 37 /** Subclasses must implement this method to print the object to the 38 * PDF file. 39 * @param catalog The object catalog to use. 40 * @param stream The writable output stream to send the output to. 41 */ 42 virtual void emitObject(SkWStream* stream, 43 const SkPDFObjNumMap& objNumMap) const = 0; 44 45 /** 46 * Adds all transitive dependencies of this object to the 47 * catalog. Implementations should respect the catalog's object 48 * substitution map. 49 */ addResources(SkPDFObjNumMap * catalog)50 virtual void addResources(SkPDFObjNumMap* catalog) const {} 51 52 /** 53 * Release all resources associated with this SkPDFObject. It is 54 * an error to call emitObject() or addResources() after calling 55 * drop(). 56 */ drop()57 virtual void drop() {} 58 ~SkPDFObject()59 virtual ~SkPDFObject() {} 60 private: 61 typedef SkRefCnt INHERITED; 62 }; 63 64 //////////////////////////////////////////////////////////////////////////////// 65 66 /** 67 A SkPDFUnion is a non-virtualized implementation of the 68 non-compound, non-specialized PDF Object types: Name, String, 69 Number, Boolean. 70 */ 71 class SkPDFUnion { 72 public: 73 // Move contstructor and assignemnt operator destroy the argument 74 // and steal their references (if needed). 75 SkPDFUnion(SkPDFUnion&& other); 76 SkPDFUnion& operator=(SkPDFUnion&& other); 77 78 ~SkPDFUnion(); 79 80 /** The following nine functions are the standard way of creating 81 SkPDFUnion objects. */ 82 83 static SkPDFUnion Int(int32_t); 84 Int(size_t v)85 static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); } 86 87 static SkPDFUnion Bool(bool); 88 89 static SkPDFUnion Scalar(SkScalar); 90 91 static SkPDFUnion ColorComponent(uint8_t); 92 93 /** These two functions do NOT take ownership of char*, and do NOT 94 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 116 static SkPDFUnion Object(sk_sp<SkPDFObject>); 117 static SkPDFUnion ObjRef(sk_sp<SkPDFObject>); 118 119 /** These two non-virtual methods mirror SkPDFObject's 120 corresponding virtuals. */ 121 void emitObject(SkWStream*, const SkPDFObjNumMap&) const; 122 void addResources(SkPDFObjNumMap*) const; 123 124 bool isName() const; 125 126 private: 127 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, 140 kColorComponent, 141 kBool, 142 kScalar, 143 kName, 144 kString, 145 kNameSkS, 146 kStringSkS, 147 kObjRef, 148 kObject, 149 }; 150 Type fType; 151 152 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 }; 158 static_assert(sizeof(SkString) == sizeof(void*), "SkString_size"); 159 160 //////////////////////////////////////////////////////////////////////////////// 161 162 #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. */ 166 class SkPDFAtom final : public SkPDFObject { 167 public: 168 void emitObject(SkWStream* stream, 169 const SkPDFObjNumMap& objNumMap) final; 170 void addResources(SkPDFObjNumMap* const final; 171 SkPDFAtom(SkPDFUnion&& v) : fValue(std::move(v) {} 172 173 private: 174 const SkPDFUnion fValue; 175 typedef SkPDFObject INHERITED; 176 }; 177 #endif // 0 178 179 //////////////////////////////////////////////////////////////////////////////// 180 181 /** \class SkPDFArray 182 183 An array object in a PDF. 184 */ 185 class SkPDFArray final : public SkPDFObject { 186 public: 187 /** Create a PDF array. Maximum length is 8191. 188 */ 189 SkPDFArray(); 190 ~SkPDFArray() override; 191 192 // The SkPDFObject interface. 193 void emitObject(SkWStream* stream, 194 const SkPDFObjNumMap& objNumMap) const override; 195 void addResources(SkPDFObjNumMap*) const override; 196 void drop() override; 197 198 /** The size of the array. 199 */ 200 int size() const; 201 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 207 /** Appends a value to the end of the array. 208 * @param value The value to add to the array. 209 */ 210 void appendInt(int32_t); 211 void appendColorComponent(uint8_t); 212 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&); 218 void appendObject(sk_sp<SkPDFObject>); 219 void appendObjRef(sk_sp<SkPDFObject>); 220 221 private: 222 SkTArray<SkPDFUnion> fValues; 223 void append(SkPDFUnion&& value); 224 SkDEBUGCODE(bool fDumped;) 225 }; 226 227 /** \class SkPDFDict 228 229 A dictionary object in a PDF. 230 */ 231 class SkPDFDict : public SkPDFObject { 232 public: 233 /** Create a PDF dictionary. 234 * @param type The value of the Type entry, nullptr for no type. 235 */ 236 explicit SkPDFDict(const char type[] = nullptr); 237 238 ~SkPDFDict() override; 239 240 // The SkPDFObject interface. 241 void emitObject(SkWStream* stream, 242 const SkPDFObjNumMap& objNumMap) const override; 243 void addResources(SkPDFObjNumMap*) const override; 244 void drop() override; 245 246 /** The size of the dictionary. 247 */ 248 int size() const; 249 250 /** Add the value to the dictionary with the given key. 251 * @param key The text of the key for this dictionary entry. 252 * @param value The value for this dictionary entry. 253 */ 254 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>); 258 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. 262 */ 263 void insertBool(const char key[], bool value); 264 void insertInt(const char key[], int32_t value); 265 void insertInt(const char key[], size_t value); 266 void insertScalar(const char key[], SkScalar value); 267 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); 271 272 /** Emit the dictionary, without the "<<" and ">>". 273 */ 274 void emitAll(SkWStream* stream, 275 const SkPDFObjNumMap& objNumMap) const; 276 277 private: 278 struct Record { 279 SkPDFUnion fKey; 280 SkPDFUnion fValue; 281 Record(SkPDFUnion&&, SkPDFUnion&&); 282 Record(Record&&) = default; 283 Record& operator=(Record&&) = default; 284 Record(const Record&) = delete; 285 Record& operator=(const Record&) = delete; 286 }; 287 SkTArray<Record> fRecords; 288 SkDEBUGCODE(bool fDumped;) 289 }; 290 291 /** \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 */ 298 class SkPDFSharedStream final : public SkPDFObject { 299 public: 300 SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data); 301 ~SkPDFSharedStream() override; dict()302 SkPDFDict* dict() { return &fDict; } 303 void emitObject(SkWStream*, 304 const SkPDFObjNumMap&) const override; 305 void addResources(SkPDFObjNumMap*) const override; 306 void drop() override; 307 308 private: 309 std::unique_ptr<SkStreamAsset> fAsset; 310 SkPDFDict fDict; 311 typedef SkPDFObject INHERITED; 312 }; 313 314 /** \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 321 class SkPDFStream final : public SkPDFObject { 322 323 public: 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 ~SkPDFStream() override; 331 dict()332 SkPDFDict* dict() { return &fDict; } 333 334 // The SkPDFObject interface. 335 void emitObject(SkWStream* stream, 336 const SkPDFObjNumMap& objNumMap) const override; 337 void addResources(SkPDFObjNumMap*) const final; 338 void drop() override; 339 340 protected: 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 348 private: 349 std::unique_ptr<SkStreamAsset> fCompressedData; 350 SkPDFDict fDict; 351 352 typedef SkPDFDict INHERITED; 353 }; 354 355 //////////////////////////////////////////////////////////////////////////////// 356 357 /** \class SkPDFObjNumMap 358 359 The PDF Object Number Map manages object numbers. It is used to 360 create the PDF cross reference table. 361 */ 362 class SkPDFObjNumMap : SkNoncopyable { 363 public: 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 370 /** 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. 372 */ 373 void addObjectRecursively(SkPDFObject* obj); 374 375 /** Get the object number for the passed object. 376 * @param obj The object of interest. 377 */ 378 int32_t getObjectNumber(SkPDFObject* obj) const; 379 objects()380 const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; } 381 382 private: 383 SkTArray<sk_sp<SkPDFObject>> fObjects; 384 SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers; 385 }; 386 387 //////////////////////////////////////////////////////////////////////////////// 388 389 #ifdef SK_PDF_IMAGE_STATS 390 extern SkAtomic<int> gDrawImageCalls; 391 extern SkAtomic<int> gJpegImageObjects; 392 extern SkAtomic<int> gRegularImageObjects; 393 extern void SkPDFImageDumpStats(); 394 #endif // SK_PDF_IMAGE_STATS 395 396 #endif 397