1 | /* |
2 | * Copyright © 2007,2008,2009,2010 Red Hat, Inc. |
3 | * Copyright © 2012,2018 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Red Hat Author(s): Behdad Esfahbod |
26 | * Google Author(s): Behdad Esfahbod |
27 | */ |
28 | |
29 | #ifndef HB_MACHINERY_HH |
30 | #define HB_MACHINERY_HH |
31 | |
32 | #include "hb.hh" |
33 | #include "hb-blob.hh" |
34 | |
35 | #include "hb-dispatch.hh" |
36 | #include "hb-sanitize.hh" |
37 | |
38 | |
39 | /* |
40 | * Casts |
41 | */ |
42 | |
43 | /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory |
44 | * location pointed to by P plus Ofs bytes. */ |
45 | template<typename Type> |
46 | static inline const Type& StructAtOffset(const void *P, unsigned int offset) |
47 | { return * reinterpret_cast<const Type*> ((const char *) P + offset); } |
48 | template<typename Type> |
49 | static inline Type& StructAtOffset(void *P, unsigned int offset) |
50 | { return * reinterpret_cast<Type*> ((char *) P + offset); } |
51 | template<typename Type> |
52 | static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) |
53 | { |
54 | #pragma GCC diagnostic push |
55 | #pragma GCC diagnostic ignored "-Wcast-align" |
56 | return * reinterpret_cast<const Type*> ((const char *) P + offset); |
57 | #pragma GCC diagnostic pop |
58 | } |
59 | template<typename Type> |
60 | static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) |
61 | { |
62 | #pragma GCC diagnostic push |
63 | #pragma GCC diagnostic ignored "-Wcast-align" |
64 | return * reinterpret_cast<Type*> ((char *) P + offset); |
65 | #pragma GCC diagnostic pop |
66 | } |
67 | |
68 | /* StructAfter<T>(X) returns the struct T& that is placed after X. |
69 | * Works with X of variable size also. X must implement get_size() */ |
70 | template<typename Type, typename TObject> |
71 | static inline const Type& StructAfter(const TObject &X) |
72 | { return StructAtOffset<Type>(&X, X.get_size()); } |
73 | template<typename Type, typename TObject> |
74 | static inline Type& StructAfter(TObject &X) |
75 | { return StructAtOffset<Type>(&X, X.get_size()); } |
76 | |
77 | |
78 | /* |
79 | * Size checking |
80 | */ |
81 | |
82 | /* Size signifying variable-sized array */ |
83 | #ifndef HB_VAR_ARRAY |
84 | #define HB_VAR_ARRAY 1 |
85 | #endif |
86 | |
87 | /* Check _assertion in a method environment */ |
88 | #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ |
89 | void _instance_assertion_on_line_##_line () const \ |
90 | { static_assert ((_assertion), ""); } |
91 | # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) |
92 | # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) |
93 | |
94 | /* Check that _code compiles in a method environment */ |
95 | #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ |
96 | void _compiles_assertion_on_line_##_line () const \ |
97 | { _code; } |
98 | # define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) |
99 | # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) |
100 | |
101 | |
102 | #define DEFINE_SIZE_STATIC(size) \ |
103 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ |
104 | unsigned int get_size () const { return (size); } \ |
105 | static constexpr unsigned null_size = (size); \ |
106 | static constexpr unsigned min_size = (size); \ |
107 | static constexpr unsigned static_size = (size) |
108 | |
109 | #define DEFINE_SIZE_UNION(size, _member) \ |
110 | DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \ |
111 | DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \ |
112 | static constexpr unsigned null_size = (size); \ |
113 | static constexpr unsigned min_size = (size) |
114 | |
115 | #define DEFINE_SIZE_MIN(size) \ |
116 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ |
117 | static constexpr unsigned null_size = (size); \ |
118 | static constexpr unsigned min_size = (size) |
119 | |
120 | #define DEFINE_SIZE_UNBOUNDED(size) \ |
121 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ |
122 | static constexpr unsigned min_size = (size) |
123 | |
124 | #define DEFINE_SIZE_ARRAY(size, array) \ |
125 | DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ |
126 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \ |
127 | static constexpr unsigned null_size = (size); \ |
128 | static constexpr unsigned min_size = (size) |
129 | |
130 | #define DEFINE_SIZE_ARRAY_SIZED(size, array) \ |
131 | unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ |
132 | DEFINE_SIZE_ARRAY(size, array) |
133 | |
134 | |
135 | |
136 | /* |
137 | * Lazy loaders. |
138 | * |
139 | * The lazy-loaders are thread-safe pointer-like objects that create their |
140 | * instead on-demand. They also support access to a "data" object that is |
141 | * necessary for creating their instance. The data object, if specified, |
142 | * is accessed via pointer math, located at a location before the position |
143 | * of the loader itself. This avoids having to store a pointer to data |
144 | * for every lazy-loader. Multiple lazy-loaders can access the same data. |
145 | */ |
146 | |
147 | template <typename Data, unsigned int WheresData> |
148 | struct hb_data_wrapper_t |
149 | { |
150 | static_assert (WheresData > 0, "" ); |
151 | |
152 | Data * get_data () const |
153 | { return *(((Data **) (void *) this) - WheresData); } |
154 | |
155 | bool is_inert () const { return !get_data (); } |
156 | |
157 | template <typename Stored, typename Subclass> |
158 | Stored * call_create () const { return Subclass::create (get_data ()); } |
159 | }; |
160 | template <> |
161 | struct hb_data_wrapper_t<void, 0> |
162 | { |
163 | bool is_inert () const { return false; } |
164 | |
165 | template <typename Stored, typename Funcs> |
166 | Stored * call_create () const { return Funcs::create (); } |
167 | }; |
168 | |
169 | template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; }; |
170 | template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; }; |
171 | |
172 | template <typename Returned, |
173 | typename Subclass = void, |
174 | typename Data = void, |
175 | unsigned int WheresData = 0, |
176 | typename Stored = Returned> |
177 | struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> |
178 | { |
179 | typedef typename hb_non_void_t<Subclass, |
180 | hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored> |
181 | >::value Funcs; |
182 | |
183 | hb_lazy_loader_t () = default; |
184 | hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete; |
185 | |
186 | void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ |
187 | void init () { instance.set_relaxed (nullptr); } |
188 | void fini () { do_destroy (instance.get_acquire ()); init (); } |
189 | |
190 | void free_instance () |
191 | { |
192 | retry: |
193 | Stored *p = instance.get_acquire (); |
194 | if (unlikely (p && !cmpexch (p, nullptr))) |
195 | goto retry; |
196 | do_destroy (p); |
197 | } |
198 | |
199 | static void do_destroy (Stored *p) |
200 | { |
201 | if (p && p != const_cast<Stored *> (Funcs::get_null ())) |
202 | Funcs::destroy (p); |
203 | } |
204 | |
205 | const Returned * operator -> () const { return get (); } |
206 | template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))> |
207 | const U & operator * () const { return *get (); } |
208 | explicit operator bool () const |
209 | { return get_stored () != Funcs::get_null (); } |
210 | template <typename C> operator const C * () const { return get (); } |
211 | |
212 | Stored * get_stored () const |
213 | { |
214 | retry: |
215 | Stored *p = this->instance.get_acquire (); |
216 | if (unlikely (!p)) |
217 | { |
218 | if (unlikely (this->is_inert ())) |
219 | return const_cast<Stored *> (Funcs::get_null ()); |
220 | |
221 | p = this->template call_create<Stored, Funcs> (); |
222 | if (unlikely (!p)) |
223 | p = const_cast<Stored *> (Funcs::get_null ()); |
224 | |
225 | if (unlikely (!cmpexch (nullptr, p))) |
226 | { |
227 | do_destroy (p); |
228 | goto retry; |
229 | } |
230 | } |
231 | return p; |
232 | } |
233 | Stored * get_stored_relaxed () const |
234 | { |
235 | return this->instance.get_relaxed (); |
236 | } |
237 | |
238 | bool cmpexch (Stored *current, Stored *value) const |
239 | { |
240 | /* This function can only be safely called directly if no |
241 | * other thread is accessing. */ |
242 | return this->instance.cmpexch (current, value); |
243 | } |
244 | |
245 | const Returned * get () const { return Funcs::convert (get_stored ()); } |
246 | const Returned * get_relaxed () const { return Funcs::convert (get_stored_relaxed ()); } |
247 | Returned * get_unconst () const { return const_cast<Returned *> (Funcs::convert (get_stored ())); } |
248 | |
249 | /* To be possibly overloaded by subclasses. */ |
250 | static Returned* convert (Stored *p) { return p; } |
251 | |
252 | /* By default null/init/fini the object. */ |
253 | static const Stored* get_null () { return &Null (Stored); } |
254 | static Stored *create (Data *data) |
255 | { |
256 | Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); |
257 | if (likely (p)) |
258 | p = new (p) Stored (data); |
259 | return p; |
260 | } |
261 | static Stored *create () |
262 | { |
263 | Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); |
264 | if (likely (p)) |
265 | p = new (p) Stored (); |
266 | return p; |
267 | } |
268 | static void destroy (Stored *p) |
269 | { |
270 | p->~Stored (); |
271 | hb_free (p); |
272 | } |
273 | |
274 | private: |
275 | /* Must only have one pointer. */ |
276 | hb_atomic_ptr_t<Stored *> instance; |
277 | }; |
278 | |
279 | /* Specializations. */ |
280 | |
281 | template <typename T, unsigned int WheresFace> |
282 | struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, |
283 | hb_face_lazy_loader_t<T, WheresFace>, |
284 | hb_face_t, WheresFace> |
285 | { |
286 | // Hack; have them here for API parity with hb_table_lazy_loader_t |
287 | hb_blob_t *get_blob () { return this->get ()->get_blob (); } |
288 | }; |
289 | |
290 | template <typename T, unsigned int WheresFace, bool core=false> |
291 | struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, |
292 | hb_table_lazy_loader_t<T, WheresFace, core>, |
293 | hb_face_t, WheresFace, |
294 | hb_blob_t> |
295 | { |
296 | static hb_blob_t *create (hb_face_t *face) |
297 | { |
298 | hb_sanitize_context_t c; |
299 | if (core) |
300 | c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs |
301 | return c.reference_table<T> (face); |
302 | } |
303 | static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } |
304 | |
305 | static const hb_blob_t *get_null () |
306 | { return hb_blob_get_empty (); } |
307 | |
308 | static const T* convert (const hb_blob_t *blob) |
309 | { return blob->as<T> (); } |
310 | |
311 | hb_blob_t* get_blob () const { return this->get_stored (); } |
312 | }; |
313 | |
314 | #define HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T(Type) \ |
315 | template <typename Subclass> \ |
316 | struct hb_##Type##_funcs_lazy_loader_t : hb_lazy_loader_t<hb_##Type##_funcs_t, Subclass> \ |
317 | { \ |
318 | static void destroy (hb_##Type##_funcs_t *p) \ |
319 | { hb_##Type##_funcs_destroy (p); } \ |
320 | static const hb_##Type##_funcs_t *get_null () \ |
321 | { return hb_##Type##_funcs_get_empty (); } \ |
322 | } |
323 | |
324 | HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (font); |
325 | HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (unicode); |
326 | HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (draw); |
327 | HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (paint); |
328 | |
329 | #undef HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T |
330 | |
331 | |
332 | #endif /* HB_MACHINERY_HH */ |
333 | |