Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-machinery.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 #include "hb-serialize.hh" | |
| 38 | |
| 39 | |
| 40 /* | |
| 41 * Casts | |
| 42 */ | |
| 43 | |
| 44 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory | |
| 45 * location pointed to by P plus Ofs bytes. */ | |
| 46 template<typename Type> | |
| 47 static inline const Type& StructAtOffset(const void *P, unsigned int offset) | |
| 48 { return * reinterpret_cast<const Type*> ((const char *) P + offset); } | |
| 49 template<typename Type> | |
| 50 static inline Type& StructAtOffset(void *P, unsigned int offset) | |
| 51 { return * reinterpret_cast<Type*> ((char *) P + offset); } | |
| 52 template<typename Type> | |
| 53 static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) | |
| 54 { | |
| 55 #pragma GCC diagnostic push | |
| 56 #pragma GCC diagnostic ignored "-Wcast-align" | |
| 57 return * reinterpret_cast<const Type*> ((const char *) P + offset); | |
| 58 #pragma GCC diagnostic pop | |
| 59 } | |
| 60 template<typename Type> | |
| 61 static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) | |
| 62 { | |
| 63 #pragma GCC diagnostic push | |
| 64 #pragma GCC diagnostic ignored "-Wcast-align" | |
| 65 return * reinterpret_cast<Type*> ((char *) P + offset); | |
| 66 #pragma GCC diagnostic pop | |
| 67 } | |
| 68 | |
| 69 /* StructAfter<T>(X) returns the struct T& that is placed after X. | |
| 70 * Works with X of variable size also. X must implement get_size() */ | |
| 71 template<typename Type, typename TObject> | |
| 72 static inline const Type& StructAfter(const TObject &X) | |
| 73 { return StructAtOffset<Type>(&X, X.get_size()); } | |
| 74 template<typename Type, typename TObject> | |
| 75 static inline Type& StructAfter(TObject &X) | |
| 76 { return StructAtOffset<Type>(&X, X.get_size()); } | |
| 77 | |
| 78 | |
| 79 /* | |
| 80 * Size checking | |
| 81 */ | |
| 82 | |
| 83 /* Size signifying variable-sized array */ | |
| 84 #ifndef HB_VAR_ARRAY | |
| 85 #define HB_VAR_ARRAY 1 | |
| 86 #endif | |
| 87 | |
| 88 /* Check _assertion in a method environment */ | |
| 89 #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ | |
| 90 void _instance_assertion_on_line_##_line () const \ | |
| 91 { static_assert ((_assertion), ""); } | |
| 92 # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) | |
| 93 # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) | |
| 94 | |
| 95 /* Check that _code compiles in a method environment */ | |
| 96 #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ | |
| 97 void _compiles_assertion_on_line_##_line () const \ | |
| 98 { _code; } | |
| 99 # define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) | |
| 100 # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) | |
| 101 | |
| 102 | |
| 103 #define DEFINE_SIZE_STATIC(size) \ | |
| 104 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ | |
| 105 unsigned int get_size () const { return (size); } \ | |
| 106 static constexpr unsigned null_size = (size); \ | |
| 107 static constexpr unsigned min_size = (size); \ | |
| 108 static constexpr unsigned static_size = (size) | |
| 109 | |
| 110 #define DEFINE_SIZE_UNION(size, _member) \ | |
| 111 DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \ | |
| 112 DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \ | |
| 113 static constexpr unsigned null_size = (size); \ | |
| 114 static constexpr unsigned min_size = (size) | |
| 115 | |
| 116 #define DEFINE_SIZE_MIN(size) \ | |
| 117 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ | |
| 118 static constexpr unsigned null_size = (size); \ | |
| 119 static constexpr unsigned min_size = (size) | |
| 120 | |
| 121 #define DEFINE_SIZE_UNBOUNDED(size) \ | |
| 122 DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ | |
| 123 static constexpr unsigned min_size = (size) | |
| 124 | |
| 125 #define DEFINE_SIZE_ARRAY(size, array) \ | |
| 126 DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ | |
| 127 DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \ | |
| 128 static constexpr unsigned null_size = (size); \ | |
| 129 static constexpr unsigned min_size = (size) | |
| 130 | |
| 131 #define DEFINE_SIZE_ARRAY_SIZED(size, array) \ | |
| 132 unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ | |
| 133 DEFINE_SIZE_ARRAY(size, array) | |
| 134 | |
| 135 | |
| 136 | |
| 137 /* | |
| 138 * Lazy loaders. | |
| 139 * | |
| 140 * The lazy-loaders are thread-safe pointer-like objects that create their | |
| 141 * instead on-demand. They also support access to a "data" object that is | |
| 142 * necessary for creating their instance. The data object, if specified, | |
| 143 * is accessed via pointer math, located at a location before the position | |
| 144 * of the loader itself. This avoids having to store a pointer to data | |
| 145 * for every lazy-loader. Multiple lazy-loaders can access the same data. | |
| 146 */ | |
| 147 | |
| 148 template <typename Data, unsigned int WheresData> | |
| 149 struct hb_data_wrapper_t | |
| 150 { | |
| 151 static_assert (WheresData > 0, ""); | |
| 152 | |
| 153 Data * get_data () const | |
| 154 { return *(((Data **) (void *) this) - WheresData); } | |
| 155 | |
| 156 bool is_inert () const { return !get_data (); } | |
| 157 | |
| 158 template <typename Stored, typename Subclass> | |
| 159 Stored * call_create () const { return Subclass::create (get_data ()); } | |
| 160 }; | |
| 161 template <> | |
| 162 struct hb_data_wrapper_t<void, 0> | |
| 163 { | |
| 164 bool is_inert () const { return false; } | |
| 165 | |
| 166 template <typename Stored, typename Funcs> | |
| 167 Stored * call_create () const { return Funcs::create (); } | |
| 168 }; | |
| 169 | |
| 170 template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; }; | |
| 171 template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; }; | |
| 172 | |
| 173 template <typename Returned, | |
| 174 typename Subclass = void, | |
| 175 typename Data = void, | |
| 176 unsigned int WheresData = 0, | |
| 177 typename Stored = Returned> | |
| 178 struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> | |
| 179 { | |
| 180 typedef typename hb_non_void_t<Subclass, | |
| 181 hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored> | |
| 182 >::value Funcs; | |
| 183 | |
| 184 void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ | |
| 185 void init () { instance.set_relaxed (nullptr); } | |
| 186 void fini () { do_destroy (instance.get_acquire ()); init (); } | |
| 187 | |
| 188 void free_instance () | |
| 189 { | |
| 190 retry: | |
| 191 Stored *p = instance.get_acquire (); | |
| 192 if (unlikely (p && !cmpexch (p, nullptr))) | |
| 193 goto retry; | |
| 194 do_destroy (p); | |
| 195 } | |
| 196 | |
| 197 static void do_destroy (Stored *p) | |
| 198 { | |
| 199 if (p && p != const_cast<Stored *> (Funcs::get_null ())) | |
| 200 Funcs::destroy (p); | |
| 201 } | |
| 202 | |
| 203 const Returned * operator -> () const { return get (); } | |
| 204 template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))> | |
| 205 const U & operator * () const { return *get (); } | |
| 206 explicit operator bool () const | |
| 207 { return get_stored () != Funcs::get_null (); } | |
| 208 template <typename C> operator const C * () const { return get (); } | |
| 209 | |
| 210 Stored * get_stored () const | |
| 211 { | |
| 212 retry: | |
| 213 Stored *p = this->instance.get_acquire (); | |
| 214 if (unlikely (!p)) | |
| 215 { | |
| 216 if (unlikely (this->is_inert ())) | |
| 217 return const_cast<Stored *> (Funcs::get_null ()); | |
| 218 | |
| 219 p = this->template call_create<Stored, Funcs> (); | |
| 220 if (unlikely (!p)) | |
| 221 p = const_cast<Stored *> (Funcs::get_null ()); | |
| 222 | |
| 223 if (unlikely (!cmpexch (nullptr, p))) | |
| 224 { | |
| 225 do_destroy (p); | |
| 226 goto retry; | |
| 227 } | |
| 228 } | |
| 229 return p; | |
| 230 } | |
| 231 Stored * get_stored_relaxed () const | |
| 232 { | |
| 233 return this->instance.get_relaxed (); | |
| 234 } | |
| 235 | |
| 236 bool cmpexch (Stored *current, Stored *value) const | |
| 237 { | |
| 238 /* This function can only be safely called directly if no | |
| 239 * other thread is accessing. */ | |
| 240 return this->instance.cmpexch (current, value); | |
| 241 } | |
| 242 | |
| 243 const Returned * get () const { return Funcs::convert (get_stored ()); } | |
| 244 const Returned * get_relaxed () const { return Funcs::convert (get_stored_relaxed ()); } | |
| 245 Returned * get_unconst () const { return const_cast<Returned *> (Funcs::convert (get_stored ())); } | |
| 246 | |
| 247 /* To be possibly overloaded by subclasses. */ | |
| 248 static Returned* convert (Stored *p) { return p; } | |
| 249 | |
| 250 /* By default null/init/fini the object. */ | |
| 251 static const Stored* get_null () { return &Null (Stored); } | |
| 252 static Stored *create (Data *data) | |
| 253 { | |
| 254 Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); | |
| 255 if (likely (p)) | |
| 256 p = new (p) Stored (data); | |
| 257 return p; | |
| 258 } | |
| 259 static Stored *create () | |
| 260 { | |
| 261 Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); | |
| 262 if (likely (p)) | |
| 263 p = new (p) Stored (); | |
| 264 return p; | |
| 265 } | |
| 266 static void destroy (Stored *p) | |
| 267 { | |
| 268 p->~Stored (); | |
| 269 hb_free (p); | |
| 270 } | |
| 271 | |
| 272 private: | |
| 273 /* Must only have one pointer. */ | |
| 274 hb_atomic_ptr_t<Stored *> instance; | |
| 275 }; | |
| 276 | |
| 277 /* Specializations. */ | |
| 278 | |
| 279 template <typename T, unsigned int WheresFace> | |
| 280 struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, | |
| 281 hb_face_lazy_loader_t<T, WheresFace>, | |
| 282 hb_face_t, WheresFace> {}; | |
| 283 | |
| 284 template <typename T, unsigned int WheresFace, bool core=false> | |
| 285 struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, | |
| 286 hb_table_lazy_loader_t<T, WheresFace, core>, | |
| 287 hb_face_t, WheresFace, | |
| 288 hb_blob_t> | |
| 289 { | |
| 290 static hb_blob_t *create (hb_face_t *face) | |
| 291 { | |
| 292 auto c = hb_sanitize_context_t (); | |
| 293 if (core) | |
| 294 c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs | |
| 295 return c.reference_table<T> (face); | |
| 296 } | |
| 297 static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } | |
| 298 | |
| 299 static const hb_blob_t *get_null () | |
| 300 { return hb_blob_get_empty (); } | |
| 301 | |
| 302 static const T* convert (const hb_blob_t *blob) | |
| 303 { return blob->as<T> (); } | |
| 304 | |
| 305 hb_blob_t* get_blob () const { return this->get_stored (); } | |
| 306 }; | |
| 307 | |
| 308 template <typename Subclass> | |
| 309 struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass> | |
| 310 { | |
| 311 static void destroy (hb_font_funcs_t *p) | |
| 312 { hb_font_funcs_destroy (p); } | |
| 313 static const hb_font_funcs_t *get_null () | |
| 314 { return hb_font_funcs_get_empty (); } | |
| 315 }; | |
| 316 template <typename Subclass> | |
| 317 struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass> | |
| 318 { | |
| 319 static void destroy (hb_unicode_funcs_t *p) | |
| 320 { hb_unicode_funcs_destroy (p); } | |
| 321 static const hb_unicode_funcs_t *get_null () | |
| 322 { return hb_unicode_funcs_get_empty (); } | |
| 323 }; | |
| 324 | |
| 325 | |
| 326 #endif /* HB_MACHINERY_HH */ |
