1 | // [Blend2D] |
2 | // 2D Vector Graphics Powered by a JIT Compiler. |
3 | // |
4 | // [License] |
5 | // Zlib - See LICENSE.md file in the package. |
6 | |
7 | #ifndef BLEND2D_BLAPI_INTERNAL_P_H |
8 | #define BLEND2D_BLAPI_INTERNAL_P_H |
9 | |
10 | // ============================================================================ |
11 | // [Dependencies] |
12 | // ============================================================================ |
13 | |
14 | #include "./blapi.h" |
15 | #include "./blapi-impl.h" |
16 | #include "./blvariant.h" |
17 | |
18 | // C Headers |
19 | // --------- |
20 | |
21 | // NOTE: Some headers are already included by <blapi.h>. This should be useful |
22 | // for creating an overview of what Blend2D really needs globally to be included. |
23 | #include <math.h> |
24 | #include <stdarg.h> |
25 | #include <stddef.h> |
26 | #include <stdint.h> |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | |
31 | // C++ Headers |
32 | // ----------- |
33 | |
34 | // We are just fine with <math.h>, however, there are some useful overloads in |
35 | // C++'s <cmath> that are nicer to use than those in <math.h>. Mostly low level |
36 | // functionality like blIsFinite() relies on <cmath> instead of <math.h>. |
37 | #include <new> |
38 | #include <cmath> |
39 | #include <limits> |
40 | |
41 | // Platform Specific Headers |
42 | // ------------------------- |
43 | |
44 | #ifdef _WIN32 |
45 | //! \cond NEVER |
46 | #ifndef WIN32_LEAN_AND_MEAN |
47 | #define WIN32_LEAN_AND_MEAN |
48 | #endif |
49 | #ifndef NOMINMAX |
50 | #define NOMINMAX |
51 | #endif |
52 | //! \endcond |
53 | |
54 | #include <windows.h> // Required to build Blend2D on Windows platform. |
55 | #include <synchapi.h> // Synchronization primitivess. |
56 | #else |
57 | #include <errno.h> // Need to access it in some cases. |
58 | #include <pthread.h> // Required to build Blend2D on POSIX compliant platforms. |
59 | #include <unistd.h> // Filesystem, sysconf, etc... |
60 | #endif |
61 | |
62 | // Some intrinsics defined by MSVC compiler are useful. Most of them should be |
63 | // used by "blsupport_p.h" that provides a lot of support functions used across |
64 | // the library. |
65 | #ifdef _MSC_VER |
66 | #include <intrin.h> |
67 | #endif |
68 | |
69 | // ============================================================================ |
70 | // [Compiler Macros] |
71 | // ============================================================================ |
72 | |
73 | // Some compilers won't optimize our stuff if we won't tell them. However, we |
74 | // have to be careful as Blend2D doesn't use fast-math by default. So when |
75 | // applicable we turn some optimizations on and off locally, but not globally. |
76 | // |
77 | // This has also a lot of downsides. For example all wrappers in "std" namespace |
78 | // are compiled with default flags so even when we force the compiler to follow |
79 | // certain behavior it would only work if we use the "original" functions and |
80 | // not those wrapped in `std` namespace (so use floor and not std::floor, etc). |
81 | #if defined(_MSC_VER) && !defined(__clang__) |
82 | #define BL_PRAGMA_FAST_MATH_PUSH __pragma(float_control(precise, off, push)) |
83 | #define BL_PRAGMA_FAST_MATH_POP __pragma(float_control(pop)) |
84 | #else |
85 | #define BL_PRAGMA_FAST_MATH_PUSH |
86 | #define BL_PRAGMA_FAST_MATH_POP |
87 | #endif |
88 | |
89 | #if defined(__clang__) || defined(__has_attribute__) |
90 | #define BL_CC_HAS_ATTRIBUTE(x) __has_attribute(x) |
91 | #else |
92 | #define BL_CC_HAS_ATTRIBUTE(x) 0 |
93 | #endif |
94 | |
95 | #if __cplusplus >= 201703L |
96 | #define BL_FALLTHROUGH [[fallthrough]]; |
97 | #else |
98 | #define BL_FALLTHROUGH /* fallthrough */ |
99 | #endif |
100 | |
101 | // ============================================================================ |
102 | // [Internal Macros] |
103 | // ============================================================================ |
104 | |
105 | //! \def BL_HIDDEN |
106 | //! |
107 | //! Decorates a function that is used across more than one source file, but |
108 | //! should never be exported. Expands to a compiler-specific code that affects |
109 | //! the visibility. |
110 | #if defined(__GNUC__) && !defined(__MINGW32__) |
111 | #define BL_HIDDEN __attribute__((__visibility__("hidden"))) |
112 | #else |
113 | #define BL_HIDDEN |
114 | #endif |
115 | |
116 | //! \def BL_OPTIMIZE |
117 | //! |
118 | //! Decorates a function that should be highly optimized by C++ compiler. In |
119 | //! general Blend2D uses "-O2" optimization level on GCC and Clang, this macro |
120 | //! would change the optimization level to "-O3" for the decorated function. |
121 | #if !defined(BL_BUILD_DEBUG) && (BL_CC_HAS_ATTRIBUTE(__optimize__) || (!defined(__clang__) && defined(__GNUC__))) |
122 | #define BL_OPTIMIZE __attribute__((__optimize__("O3"))) |
123 | #else |
124 | #define BL_OPTIMIZE |
125 | #endif |
126 | |
127 | //! \def BL_NOINLINE |
128 | //! |
129 | //! Decorates a function that should never be inlined. Sometimes used by Blend2D |
130 | //! to decorate functions that are either called rarely or that are called from |
131 | //! other code in corner cases - like buffer reallocation, etc... |
132 | #if defined(__GNUC__) |
133 | #define BL_NOINLINE __attribute__((noinline)) |
134 | #elif defined(_MSC_VER) |
135 | #define BL_NOINLINE __declspec(noinline) |
136 | #else |
137 | #define BL_NOINLINE |
138 | #endif |
139 | |
140 | //! \def BL_STDCALL |
141 | //! |
142 | //! Calling convention used by Windows. |
143 | #if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__) |
144 | #define BL_STDCALL __attribute__((__stdcall__)) |
145 | #elif defined(_MSC_VER) |
146 | #define BL_STDCALL __stdcall |
147 | #else |
148 | #define BL_STDCALL |
149 | #endif |
150 | |
151 | #define BL_NONCOPYABLE(...) \ |
152 | __VA_ARGS__(const __VA_ARGS__& other) = delete; \ |
153 | __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; |
154 | |
155 | #define BL_UNUSED(X) (void)(X) |
156 | |
157 | #define BL_ARRAY_SIZE(X) uint32_t(sizeof(X) / sizeof(X[0])) |
158 | #define BL_OFFSET_OF(STRUCT, MEMBER) ((int)(offsetof(STRUCT, MEMBER))) |
159 | |
160 | //! \def BL_NOT_REACHED() |
161 | //! |
162 | //! Run-time assertion used in code that should never be reached. |
163 | #ifdef BL_BUILD_DEBUG |
164 | #define BL_NOT_REACHED() \ |
165 | do { \ |
166 | blRuntimeAssertionFailure(__FILE__, __LINE__, \ |
167 | "Unreachable code-path reached"); \ |
168 | } while (0) |
169 | #else |
170 | #define BL_NOT_REACHED() BL_ASSUME(0) |
171 | #endif |
172 | |
173 | //! Decorates a base class that has virtual functions. |
174 | #define BL_OVERRIDE_NEW_DELETE(TYPE) \ |
175 | BL_INLINE void* operator new(size_t n) noexcept { return malloc(n); } \ |
176 | BL_INLINE void operator delete(void* p) noexcept { if (p) free(p); } \ |
177 | \ |
178 | BL_INLINE void* operator new(size_t, void* p) noexcept { return p; } \ |
179 | BL_INLINE void operator delete(void*, void*) noexcept {} |
180 | |
181 | // ============================================================================ |
182 | // [Forward Declarations] |
183 | // ============================================================================ |
184 | |
185 | struct BLRuntimeContext; |
186 | |
187 | // ============================================================================ |
188 | // [Internal Constants] |
189 | // ============================================================================ |
190 | |
191 | //! Internal constants and limits used across the library. |
192 | enum BLInternalConsts : uint32_t { |
193 | // -------------------------------------------------------------------------- |
194 | // System allocator properties and some limits used by Blend2D. |
195 | // -------------------------------------------------------------------------- |
196 | |
197 | //! Host memory allocator overhead (estimated). |
198 | BL_ALLOC_OVERHEAD = uint32_t(sizeof(void*)) * 4, |
199 | //! Host memory allocator alignment (must match!). |
200 | BL_ALLOC_ALIGNMENT = 8, |
201 | |
202 | //! Limits a doubling of a container size after the limit size [in bytes] is |
203 | //! reached [8MB]. After the size is reached the container will grow in [8MB] |
204 | //! chunks. |
205 | BL_ALLOC_GROW_LIMIT = 1 << 23, |
206 | |
207 | // -------------------------------------------------------------------------- |
208 | // Alloc hints are specified in bytes. Each container will be allocated to |
209 | // `BL_ALLOC_HINT_...` bytes initially when a first item is added |
210 | // to it. |
211 | // -------------------------------------------------------------------------- |
212 | |
213 | //! Initial size of BLStringImpl of a newly allocated string [in bytes]. |
214 | BL_ALLOC_HINT_STRING = 64, |
215 | //! Initial size of BLArrayImpl of a newly allocated array [in bytes]. |
216 | BL_ALLOC_HINT_ARRAY = 128, |
217 | //! Initial size of BLRegionImpl of a newly allocated region [in bytes]. |
218 | BL_ALLOC_HINT_REGION = 256, |
219 | //! Initial size of BLPathImpl of a newly allocated path [in bytes]. |
220 | BL_ALLOC_HINT_PATH2D = 512, |
221 | //! Initial size of BLGradientImpl of a newly allocated gradient [in bytes]. |
222 | BL_ALLOC_HINT_GRADIENT = 256, |
223 | |
224 | //! To make checks for APPEND operation easier. |
225 | BL_MODIFY_OP_APPEND_START = 2, |
226 | //! Mask that can be used to check whether `BLModifyOp` has a grow hint. |
227 | BL_MODIFY_OP_GROW_MASK = 0x1, |
228 | |
229 | //! Minimum vertices to amortize the check of a matrix type. |
230 | BL_MATRIX_TYPE_MINIMUM_SIZE = 16, |
231 | |
232 | //! Maximum number of faces per a single font collection. |
233 | BL_FONT_LOADER_MAX_FACE_COUNT = 256 |
234 | |
235 | }; |
236 | |
237 | //! Analysis result that describes whether an unknown input is conforming. |
238 | enum BLDataAnalysis : uint32_t { |
239 | //! The input data is conforming (stored exactly as expected). |
240 | BL_DATA_ANALYSIS_CONFORMING = 0, // Must be 0 |
241 | //! The input data is valid, but non-conforming (must be processed). |
242 | BL_DATA_ANALYSIS_NON_CONFORMING = 1, // Must be 1 |
243 | //! The input data contains an invalid value. |
244 | BL_DATA_ANALYSIS_INVALID_VALUE = 2 |
245 | }; |
246 | |
247 | // ============================================================================ |
248 | // [Internal Functions] |
249 | // ============================================================================ |
250 | |
251 | template<typename T> |
252 | struct BLInternalCastImpl { T Type; }; |
253 | |
254 | //! Casts a public `T` type into an internal implementation/data of that type. |
255 | //! For example `BLPathImpl` would be casted to `BLInternalPathImpl`. Used |
256 | //! by Blend2D as a shortcut to prevent using more verbose `static_cast<>` in |
257 | //! code that requires a lot of such casts (in most cases public API which is |
258 | //! then casting public interfaces into an internal ones). |
259 | template<typename T> |
260 | constexpr typename BLInternalCastImpl<T>::Type* blInternalCast(T* something) noexcept { |
261 | return static_cast<typename BLInternalCastImpl<T>::Type*>(something); |
262 | } |
263 | |
264 | //! \overload |
265 | template<typename T> |
266 | constexpr const typename BLInternalCastImpl<T>::Type* blInternalCast(const T* something) noexcept { |
267 | return static_cast<const typename BLInternalCastImpl<T>::Type*>(something); |
268 | } |
269 | |
270 | //! Checks whether `dataAccessFlags` is valid. |
271 | static BL_INLINE bool blDataAccessFlagsIsValid(uint32_t dataAccessFlags) noexcept { |
272 | return dataAccessFlags == BL_DATA_ACCESS_READ || |
273 | dataAccessFlags == BL_DATA_ACCESS_RW; |
274 | } |
275 | |
276 | //! Assigns a built-in none implementation `impl` to `blNone` - a built-in |
277 | //! array that contains all null instances provided by Blend2D. Any code that |
278 | //! assigns to `blNone` array must use this function as it's then easy to find. |
279 | template<typename T> |
280 | static BL_INLINE void blAssignBuiltInNull(T* impl) noexcept { |
281 | *reinterpret_cast<T**>((void **)blNone + impl->implType) = impl; |
282 | } |
283 | |
284 | template<typename T> |
285 | static BL_INLINE void blCallCtor(T& t) noexcept { |
286 | // Only needed by MSVC as otherwise it could generate null-pointer check |
287 | // before calling the constructor (as null pointer is allowed). GCC and |
288 | // clang can emit a "-Wtautological-undefined-compare" warning and that's |
289 | // the main reason it's only enabled for MSVC. |
290 | #if defined(_MSC_VER) && !defined(__clang__) |
291 | BL_ASSUME(&t != nullptr); |
292 | #endif |
293 | |
294 | new(&t) T(); |
295 | } |
296 | |
297 | template<typename T> |
298 | static BL_INLINE void blCallDtor(T& t) noexcept { |
299 | t.~T(); |
300 | } |
301 | |
302 | //! \} |
303 | //! \endcond |
304 | |
305 | #endif // BLEND2D_BLAPI_INTERNAL_P_H |
306 | |