1 // Copyright 2018 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 #ifndef SkPDFUnion_DEFINED
4 #define SkPDFUnion_DEFINED
5 
6 #include "src/pdf/SkPDFTypes.h"
7 
8 template <class T>
9 class SkStorageFor {
10 public:
get()11     const T& get() const { return *reinterpret_cast<const T*>(&fStore); }
get()12     T& get() { return *reinterpret_cast<T*>(&fStore); }
13     // Up to caller to keep track of status.
init(Args &&...args)14     template<class... Args> void init(Args&&... args) {
15         new (&this->get()) T(std::forward<Args>(args)...);
16     }
destroy()17     void destroy() { this->get().~T(); }
18 private:
19     typename std::aligned_storage<sizeof(T), alignof(T)>::type fStore;
20 };
21 
22 // Exposed for unit testing.
23 void SkPDFWriteString(SkWStream* wStream, const char* cin, size_t len);
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 
27 /**
28    A SkPDFUnion is a non-virtualized implementation of the
29    non-compound, non-specialized PDF Object types: Name, String,
30    Number, Boolean.
31  */
32 class SkPDFUnion {
33 public:
34     // Move contstructor and assignment operator destroy the argument
35     // and steal their references (if needed).
36     SkPDFUnion(SkPDFUnion&& other);
37     SkPDFUnion& operator=(SkPDFUnion&& other);
38 
39     ~SkPDFUnion();
40 
41     /** The following nine functions are the standard way of creating
42         SkPDFUnion objects. */
43 
44     static SkPDFUnion Int(int32_t);
45 
Int(size_t v)46     static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); }
47 
48     static SkPDFUnion Bool(bool);
49 
50     static SkPDFUnion Scalar(SkScalar);
51 
52     static SkPDFUnion ColorComponent(uint8_t);
53 
54     static SkPDFUnion ColorComponentF(float);
55 
56     /** These two functions do NOT take ownership of char*, and do NOT
57         copy the string.  Suitable for passing in static const
58         strings. For example:
59           SkPDFUnion n = SkPDFUnion::Name("Length");
60           SkPDFUnion u = SkPDFUnion::String("Identity"); */
61 
62     /** SkPDFUnion::Name(const char*) assumes that the passed string
63         is already a valid name (that is: it has no control or
64         whitespace characters).  This will not copy the name. */
65     static SkPDFUnion Name(const char*);
66 
67     /** SkPDFUnion::String will encode the passed string.  This will
68         not copy the name. */
69     static SkPDFUnion String(const char*);
70 
71     /** SkPDFUnion::Name(SkString) does not assume that the
72         passed string is already a valid name and it will escape the
73         string. */
74     static SkPDFUnion Name(SkString);
75 
76     /** SkPDFUnion::String will encode the passed string. */
77     static SkPDFUnion String(SkString);
78 
79     static SkPDFUnion Object(std::unique_ptr<SkPDFObject>);
80 
81     static SkPDFUnion Ref(SkPDFIndirectReference);
82 
83     /** These two non-virtual methods mirror SkPDFObject's
84         corresponding virtuals. */
85     void emitObject(SkWStream*) const;
86 
87     bool isName() const;
88 
89 private:
90     union {
91         int32_t fIntValue;
92         bool fBoolValue;
93         SkScalar fScalarValue;
94         const char* fStaticString;
95         SkStorageFor<SkString> fSkString;
96         SkPDFObject* fObject;
97     };
98     enum class Type : char {
99         /** It is an error to call emitObject() or addResources() on an
100             kDestroyed object. */
101         kDestroyed = 0,
102         kInt,
103         kColorComponent,
104         kColorComponentF,
105         kBool,
106         kScalar,
107         kName,
108         kString,
109         kNameSkS,
110         kStringSkS,
111         kObject,
112         kRef,
113     };
114     Type fType;
115 
116     SkPDFUnion(Type);
117     SkPDFUnion(Type, int32_t);
118     SkPDFUnion(Type, bool);
119     SkPDFUnion(Type, SkScalar);
120     SkPDFUnion(Type, SkString);
121     // We do not now need copy constructor and copy assignment, so we
122     // will disable this functionality.
123     SkPDFUnion& operator=(const SkPDFUnion&) = delete;
124     SkPDFUnion(const SkPDFUnion&) = delete;
125 };
126 static_assert(sizeof(SkString) == sizeof(void*), "SkString_size");
127 
128 #endif  // SkPDFUnion_DEFINED
129