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 "SkStream.h" 15 #include "SkString.h" 16 #include "SkTDArray.h" 17 #include "SkTHash.h" 18 #include "SkTypes.h" 19 20 class SkPDFObjNumMap; 21 class SkPDFObject; 22 class SkPDFSubstituteMap; 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 // TODO(halcanary): make this method const 43 virtual void emitObject(SkWStream* stream, 44 const SkPDFObjNumMap& objNumMap, 45 const SkPDFSubstituteMap& substitutes) const = 0; 46 47 /** 48 * Adds all transitive dependencies of this object to the 49 * catalog. Implementations should respect the catalog's object 50 * substitution map. 51 */ addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes)52 virtual void addResources(SkPDFObjNumMap* catalog, 53 const SkPDFSubstituteMap& substitutes) const {} 54 55 private: 56 typedef SkRefCnt INHERITED; 57 }; 58 59 //////////////////////////////////////////////////////////////////////////////// 60 61 /** 62 A SkPDFUnion is a non-virtualized implementation of the 63 non-compound, non-specialized PDF Object types: Name, String, 64 Number, Boolean. 65 */ 66 class SkPDFUnion { 67 public: 68 // u.move() is analogous to std::move(u). It returns an rvalue. move()69 SkPDFUnion move() { return static_cast<SkPDFUnion&&>(*this); } 70 // Move contstructor and assignemnt operator destroy the argument 71 // and steal their references (if needed). 72 SkPDFUnion(SkPDFUnion&& other); 73 SkPDFUnion& operator=(SkPDFUnion&& other); 74 75 ~SkPDFUnion(); 76 77 /** The following nine functions are the standard way of creating 78 SkPDFUnion objects. */ 79 80 static SkPDFUnion Int(int32_t); 81 Int(size_t v)82 static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); } 83 84 static SkPDFUnion Bool(bool); 85 86 static SkPDFUnion Scalar(SkScalar); 87 88 /** These two functions do NOT take ownership of ptr, and do NOT 89 copy the string. Suitable for passing in static const 90 strings. For example: 91 SkPDFUnion n = SkPDFUnion::Name("Length"); 92 SkPDFUnion u = SkPDFUnion::String("Identity"); */ 93 94 /** SkPDFUnion::Name(const char*) assumes that the passed string 95 is already a valid name (that is: it has no control or 96 whitespace characters). This will not copy the name. */ 97 static SkPDFUnion Name(const char*); 98 99 /** SkPDFUnion::String will encode the passed string. This will 100 not copy the name. */ 101 static SkPDFUnion String(const char*); 102 103 /** SkPDFUnion::Name(const SkString&) does not assume that the 104 passed string is already a valid name and it will escape the 105 string. */ 106 static SkPDFUnion Name(const SkString&); 107 108 /** SkPDFUnion::String will encode the passed string. */ 109 static SkPDFUnion String(const SkString&); 110 111 /** This function DOES take ownership of the object. E.g. 112 SkAutoTUnref<SkPDFDict> dict(new SkPDFDict); 113 dict->insert(.....); 114 SkPDFUnion u = SkPDFUnion::Object(dict.detach()) */ 115 static SkPDFUnion Object(SkPDFObject*); 116 117 /** This function DOES take ownership of the object. E.g. 118 SkAutoTUnref<SkPDFBitmap> image( 119 SkPDFBitmap::Create(fCanon, bitmap)); 120 SkPDFUnion u = SkPDFUnion::ObjRef(image.detach()) */ 121 static SkPDFUnion ObjRef(SkPDFObject*); 122 123 /** These two non-virtual methods mirror SkPDFObject's 124 corresponding virtuals. */ 125 void emitObject(SkWStream*, 126 const SkPDFObjNumMap&, 127 const SkPDFSubstituteMap&) const; 128 void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const; 129 130 bool isName() const; 131 132 private: 133 union { 134 int32_t fIntValue; 135 bool fBoolValue; 136 SkScalar fScalarValue; 137 const char* fStaticString; 138 char fSkString[sizeof(SkString)]; 139 SkPDFObject* fObject; 140 }; 141 enum class Type : char { 142 /** It is an error to call emitObject() or addResources() on an 143 kDestroyed object. */ 144 kDestroyed = 0, 145 kInt, 146 kBool, 147 kScalar, 148 kName, 149 kString, 150 kNameSkS, 151 kStringSkS, 152 kObjRef, 153 kObject, 154 }; 155 Type fType; 156 157 SkPDFUnion(Type); 158 // We do not now need copy constructor and copy assignment, so we 159 // will disable this functionality. 160 SkPDFUnion& operator=(const SkPDFUnion&) = delete; 161 SkPDFUnion(const SkPDFUnion&) = delete; 162 }; 163 static_assert(sizeof(SkString) == sizeof(void*), "SkString_size"); 164 165 //////////////////////////////////////////////////////////////////////////////// 166 167 #if 0 // Enable if needed. 168 /** This class is a SkPDFUnion with SkPDFObject virtuals attached. 169 The only use case of this is when a non-compound PDF object is 170 referenced indirectly. */ 171 class SkPDFAtom final : public SkPDFObject { 172 public: 173 void emitObject(SkWStream* stream, 174 const SkPDFObjNumMap& objNumMap, 175 const SkPDFSubstituteMap& substitutes) final; 176 void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final; 177 SkPDFAtom(SkPDFUnion&& v) : fValue(v.move()) {} 178 179 private: 180 const SkPDFUnion fValue; 181 typedef SkPDFObject INHERITED; 182 }; 183 #endif // 0 184 185 //////////////////////////////////////////////////////////////////////////////// 186 187 /** \class SkPDFArray 188 189 An array object in a PDF. 190 */ 191 class SkPDFArray final : public SkPDFObject { 192 public: 193 static const int kMaxLen = 8191; 194 195 /** Create a PDF array. Maximum length is 8191. 196 */ 197 SkPDFArray(); 198 virtual ~SkPDFArray(); 199 200 // The SkPDFObject interface. 201 void emitObject(SkWStream* stream, 202 const SkPDFObjNumMap& objNumMap, 203 const SkPDFSubstituteMap& substitutes) const override; 204 void addResources(SkPDFObjNumMap*, 205 const SkPDFSubstituteMap&) const override; 206 207 /** The size of the array. 208 */ 209 int size() const; 210 211 /** Preallocate space for the given number of entries. 212 * @param length The number of array slots to preallocate. 213 */ 214 void reserve(int length); 215 216 /** Appends a value to the end of the array. 217 * @param value The value to add to the array. 218 */ 219 void appendInt(int32_t); 220 void appendBool(bool); 221 void appendScalar(SkScalar); 222 void appendName(const char[]); 223 void appendName(const SkString&); 224 void appendString(const char[]); 225 void appendString(const SkString&); 226 /** appendObject and appendObjRef take ownership of the passed object */ 227 void appendObject(SkPDFObject*); 228 void appendObjRef(SkPDFObject*); 229 230 private: 231 SkTDArray<SkPDFUnion> fValues; 232 void append(SkPDFUnion&& value); 233 typedef SkPDFObject INHERITED; 234 }; 235 236 /** \class SkPDFDict 237 238 A dictionary object in a PDF. 239 */ 240 class SkPDFDict : public SkPDFObject { 241 public: 242 /** Create a PDF dictionary. Maximum number of entries is 4095. 243 */ 244 SkPDFDict(); 245 246 /** Create a PDF dictionary with a Type entry. 247 * @param type The value of the Type entry. 248 */ 249 explicit SkPDFDict(const char type[]); 250 251 virtual ~SkPDFDict(); 252 253 // The SkPDFObject interface. 254 void emitObject(SkWStream* stream, 255 const SkPDFObjNumMap& objNumMap, 256 const SkPDFSubstituteMap& substitutes) const override; 257 void addResources(SkPDFObjNumMap*, 258 const SkPDFSubstituteMap&) const override; 259 260 /** The size of the dictionary. 261 */ 262 int size() const; 263 264 /** Add the value to the dictionary with the given key. Takes 265 * ownership of the object. 266 * @param key The text of the key for this dictionary entry. 267 * @param value The value for this dictionary entry. 268 */ 269 void insertObject(const char key[], SkPDFObject* value); 270 void insertObject(const SkString& key, SkPDFObject* value); 271 void insertObjRef(const char key[], SkPDFObject* value); 272 void insertObjRef(const SkString& key, SkPDFObject* value); 273 274 /** Add the value to the dictionary with the given key. 275 * @param key The text of the key for this dictionary entry. 276 * @param value The value for this dictionary entry. 277 */ 278 void insertBool(const char key[], bool value); 279 void insertInt(const char key[], int32_t value); 280 void insertInt(const char key[], size_t value); 281 void insertScalar(const char key[], SkScalar value); 282 void insertName(const char key[], const char nameValue[]); 283 void insertName(const char key[], const SkString& nameValue); 284 void insertString(const char key[], const char value[]); 285 void insertString(const char key[], const SkString& value); 286 287 /** Remove all entries from the dictionary. 288 */ 289 void clear(); 290 291 /** Emit the dictionary, without the "<<" and ">>". 292 */ 293 void emitAll(SkWStream* stream, 294 const SkPDFObjNumMap& objNumMap, 295 const SkPDFSubstituteMap& substitutes) const; 296 297 private: 298 struct Record { 299 SkPDFUnion fKey; 300 SkPDFUnion fValue; 301 }; 302 SkTDArray<Record> fRecords; 303 static const int kMaxLen = 4095; 304 305 void set(SkPDFUnion&& name, SkPDFUnion&& value); 306 307 typedef SkPDFObject INHERITED; 308 }; 309 310 /** \class SkPDFSharedStream 311 312 This class takes an asset and assumes that it is backed by 313 long-lived shared data (for example, an open file 314 descriptor). That is: no memory savings can be made by holding on 315 to a compressed version instead. 316 */ 317 class SkPDFSharedStream final : public SkPDFObject { 318 public: 319 // Takes ownership of asset. SkPDFSharedStream(SkStreamAsset * data)320 SkPDFSharedStream(SkStreamAsset* data) : fAsset(data), fDict(new SkPDFDict) { SkASSERT(data); } dict()321 SkPDFDict* dict() { return fDict; } 322 void emitObject(SkWStream*, 323 const SkPDFObjNumMap&, 324 const SkPDFSubstituteMap&) const override; 325 void addResources(SkPDFObjNumMap*, 326 const SkPDFSubstituteMap&) const override; 327 328 private: 329 SkAutoTDelete<SkStreamAsset> fAsset; 330 SkAutoTUnref<SkPDFDict> fDict; 331 typedef SkPDFObject INHERITED; 332 }; 333 334 //////////////////////////////////////////////////////////////////////////////// 335 336 /** \class SkPDFObjNumMap 337 338 The PDF Object Number Map manages object numbers. It is used to 339 create the PDF cross reference table. 340 */ 341 class SkPDFObjNumMap : SkNoncopyable { 342 public: 343 /** Add the passed object to the catalog. 344 * @param obj The object to add. 345 * @return True iff the object was not already added to the catalog. 346 */ 347 bool addObject(SkPDFObject* obj); 348 349 /** Add the passed object to the catalog, as well as all its dependencies. 350 * @param obj The object to add. If nullptr, this is a noop. 351 * @param subs Will be passed to obj->addResources(). 352 */ 353 void addObjectRecursively(SkPDFObject* obj, const SkPDFSubstituteMap& subs); 354 355 /** Get the object number for the passed object. 356 * @param obj The object of interest. 357 */ 358 int32_t getObjectNumber(SkPDFObject* obj) const; 359 objects()360 const SkTDArray<SkPDFObject*>& objects() const { return fObjects; } 361 362 private: 363 SkTDArray<SkPDFObject*> fObjects; 364 SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers; 365 }; 366 367 //////////////////////////////////////////////////////////////////////////////// 368 369 /** \class SkPDFSubstituteMap 370 371 The PDF Substitute Map manages substitute objects and owns the 372 substitutes. 373 */ 374 class SkPDFSubstituteMap : SkNoncopyable { 375 public: 376 ~SkPDFSubstituteMap(); 377 /** Set substitute object for the passed object. 378 Refs substitute. 379 */ 380 void setSubstitute(SkPDFObject* original, SkPDFObject* substitute); 381 382 /** Find and return any substitute object set for the passed object. If 383 * there is none, return the passed object. 384 */ 385 SkPDFObject* getSubstitute(SkPDFObject* object) const; 386 operator()387 SkPDFObject* operator()(SkPDFObject* o) const { 388 return this->getSubstitute(o); 389 } 390 391 private: 392 SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap; 393 }; 394 395 #ifdef SK_PDF_IMAGE_STATS 396 extern SkAtomic<int> gDrawImageCalls; 397 extern SkAtomic<int> gJpegImageObjects; 398 extern SkAtomic<int> gRegularImageObjects; 399 extern void SkPDFImageDumpStats(); 400 #endif // SK_PDF_IMAGE_STATS 401 402 #endif 403