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
185struct BLRuntimeContext;
186
187// ============================================================================
188// [Internal Constants]
189// ============================================================================
190
191//! Internal constants and limits used across the library.
192enum 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.
238enum 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
251template<typename T>
252struct 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).
259template<typename T>
260constexpr typename BLInternalCastImpl<T>::Type* blInternalCast(T* something) noexcept {
261 return static_cast<typename BLInternalCastImpl<T>::Type*>(something);
262}
263
264//! \overload
265template<typename T>
266constexpr 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.
271static 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.
279template<typename T>
280static BL_INLINE void blAssignBuiltInNull(T* impl) noexcept {
281 *reinterpret_cast<T**>((void **)blNone + impl->implType) = impl;
282}
283
284template<typename T>
285static 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
297template<typename T>
298static BL_INLINE void blCallDtor(T& t) noexcept {
299 t.~T();
300}
301
302//! \}
303//! \endcond
304
305#endif // BLEND2D_BLAPI_INTERNAL_P_H
306