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 /** Preallocate space for n key-value pairs */ 251 void reserve(int n); 252 253 /** Add the value to the dictionary with the given key. 254 * @param key The text of the key for this dictionary entry. 255 * @param value The value for this dictionary entry. 256 */ 257 void insertObject(const char key[], sk_sp<SkPDFObject>); 258 void insertObject(const SkString& key, sk_sp<SkPDFObject>); 259 void insertObjRef(const char key[], sk_sp<SkPDFObject>); 260 void insertObjRef(const SkString& key, sk_sp<SkPDFObject>); 261 262 /** Add the value to the dictionary with the given key. 263 * @param key The text of the key for this dictionary entry. 264 * @param value The value for this dictionary entry. 265 */ 266 void insertBool(const char key[], bool value); 267 void insertInt(const char key[], int32_t value); 268 void insertInt(const char key[], size_t value); 269 void insertScalar(const char key[], SkScalar value); 270 void insertName(const char key[], const char nameValue[]); 271 void insertName(const char key[], const SkString& nameValue); 272 void insertString(const char key[], const char value[]); 273 void insertString(const char key[], const SkString& value); 274 275 /** Emit the dictionary, without the "<<" and ">>". 276 */ 277 void emitAll(SkWStream* stream, 278 const SkPDFObjNumMap& objNumMap) const; 279 280 private: 281 struct Record { 282 SkPDFUnion fKey; 283 SkPDFUnion fValue; 284 }; 285 SkTArray<Record> fRecords; 286 SkDEBUGCODE(bool fDumped;) 287 }; 288 289 /** \class SkPDFSharedStream 290 291 This class takes an asset and assumes that it is backed by 292 long-lived shared data (for example, an open file 293 descriptor). That is: no memory savings can be made by holding on 294 to a compressed version instead. 295 */ 296 class SkPDFSharedStream final : public SkPDFObject { 297 public: 298 SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data); 299 ~SkPDFSharedStream() override; dict()300 SkPDFDict* dict() { return &fDict; } 301 void emitObject(SkWStream*, 302 const SkPDFObjNumMap&) const override; 303 void addResources(SkPDFObjNumMap*) const override; 304 void drop() override; 305 306 private: 307 std::unique_ptr<SkStreamAsset> fAsset; 308 SkPDFDict fDict; 309 typedef SkPDFObject INHERITED; 310 }; 311 312 /** \class SkPDFStream 313 314 This class takes an asset and assumes that it is the only owner of 315 the asset's data. It immediately compresses the asset to save 316 memory. 317 */ 318 319 class SkPDFStream final : public SkPDFObject { 320 321 public: 322 /** Create a PDF stream. A Length entry is automatically added to the 323 * stream dictionary. 324 * @param data The data part of the stream. 325 * @param stream The data part of the stream. */ 326 explicit SkPDFStream(sk_sp<SkData> data); 327 explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream); 328 ~SkPDFStream() override; 329 dict()330 SkPDFDict* dict() { return &fDict; } 331 332 // The SkPDFObject interface. 333 void emitObject(SkWStream* stream, 334 const SkPDFObjNumMap& objNumMap) const override; 335 void addResources(SkPDFObjNumMap*) const final; 336 void drop() override; 337 338 protected: 339 /* Create a PDF stream with no data. The setData method must be called to 340 * set the data. */ 341 SkPDFStream(); 342 343 /** Only call this function once. */ 344 void setData(std::unique_ptr<SkStreamAsset> stream); 345 346 private: 347 std::unique_ptr<SkStreamAsset> fCompressedData; 348 SkPDFDict fDict; 349 350 typedef SkPDFDict INHERITED; 351 }; 352 353 //////////////////////////////////////////////////////////////////////////////// 354 355 /** \class SkPDFObjNumMap 356 357 The PDF Object Number Map manages object numbers. It is used to 358 create the PDF cross reference table. 359 */ 360 class SkPDFObjNumMap : SkNoncopyable { 361 public: 362 /** Add the passed object to the catalog. 363 * @param obj The object to add. 364 * @return True iff the object was not already added to the catalog. 365 */ 366 bool addObject(SkPDFObject* obj); 367 368 /** Add the passed object to the catalog, as well as all its dependencies. 369 * @param obj The object to add. If nullptr, this is a noop. 370 */ 371 void addObjectRecursively(SkPDFObject* obj); 372 373 /** Get the object number for the passed object. 374 * @param obj The object of interest. 375 */ 376 int32_t getObjectNumber(SkPDFObject* obj) const; 377 objects()378 const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; } 379 380 private: 381 SkTArray<sk_sp<SkPDFObject>> fObjects; 382 SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers; 383 }; 384 385 //////////////////////////////////////////////////////////////////////////////// 386 387 #ifdef SK_PDF_IMAGE_STATS 388 extern SkAtomic<int> gDrawImageCalls; 389 extern SkAtomic<int> gJpegImageObjects; 390 extern SkAtomic<int> gRegularImageObjects; 391 extern void SkPDFImageDumpStats(); 392 #endif // SK_PDF_IMAGE_STATS 393 394 #endif 395