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 | #include "./blapi-build_p.h" |
8 | #include "./blmatrix_p.h" |
9 | #include "./blpattern_p.h" |
10 | #include "./blruntime_p.h" |
11 | #include "./blsupport_p.h" |
12 | #include "./blvariant.h" |
13 | |
14 | // ============================================================================ |
15 | // [Global Variables] |
16 | // ============================================================================ |
17 | |
18 | static BLWrap<BLInternalPatternImpl> blNullPatternImpl; |
19 | |
20 | static constexpr const BLRectI blPatternNoArea(0, 0, 0, 0); |
21 | |
22 | // ============================================================================ |
23 | // [BLPattern - Internals] |
24 | // ============================================================================ |
25 | |
26 | static BL_INLINE BLInternalPatternImpl* blPatternImplNew(const BLImageCore* image, const BLRectI* area, uint32_t extendMode, uint32_t matrixType, const BLMatrix2D* matrix) noexcept { |
27 | uint16_t memPoolData; |
28 | BLInternalPatternImpl* impl = blRuntimeAllocImplT<BLInternalPatternImpl>(sizeof(BLInternalPatternImpl), &memPoolData); |
29 | |
30 | if (BL_UNLIKELY(!impl)) |
31 | return impl; |
32 | |
33 | blImplInit(impl, BL_IMPL_TYPE_PATTERN, BL_IMPL_TRAIT_MUTABLE, memPoolData); |
34 | impl->image.impl = blImplIncRef(image->impl); |
35 | impl->reservedHeader[0] = nullptr; |
36 | impl->reservedHeader[1] = nullptr; |
37 | impl->patternType = 0; |
38 | impl->extendMode = uint8_t(extendMode); |
39 | impl->matrixType = uint8_t(matrixType); |
40 | impl->reserved[0] = 0; |
41 | impl->matrix = *matrix; |
42 | impl->area = *area; |
43 | |
44 | return impl; |
45 | } |
46 | |
47 | // Cannot be static, called by `BLVariant` implementation. |
48 | BLResult blPatternImplDelete(BLPatternImpl* impl_) noexcept { |
49 | BLInternalPatternImpl* impl = blInternalCast(impl_); |
50 | blImageReset(&impl->image); |
51 | |
52 | uint8_t* implBase = reinterpret_cast<uint8_t*>(impl); |
53 | size_t implSize = sizeof(BLInternalPatternImpl); |
54 | uint32_t implTraits = impl->implTraits; |
55 | uint32_t memPoolData = impl->memPoolData; |
56 | |
57 | if (implTraits & BL_IMPL_TRAIT_EXTERNAL) { |
58 | implSize += sizeof(BLExternalImplPreface); |
59 | implBase -= sizeof(BLExternalImplPreface); |
60 | blImplDestroyExternal(impl); |
61 | } |
62 | |
63 | if (implTraits & BL_IMPL_TRAIT_FOREIGN) |
64 | return BL_SUCCESS; |
65 | else |
66 | return blRuntimeFreeImpl(implBase, implSize, memPoolData); |
67 | } |
68 | |
69 | static BL_INLINE BLResult blPatternImplRelease(BLInternalPatternImpl* impl) noexcept { |
70 | if (blImplDecRefAndTest(impl)) |
71 | return blPatternImplDelete(impl); |
72 | return BL_SUCCESS; |
73 | } |
74 | |
75 | static BL_NOINLINE BLResult blPatternMakeMutableCopyOf(BLPatternCore* self, BLInternalPatternImpl* impl) noexcept { |
76 | BLInternalPatternImpl* newI = blPatternImplNew(&impl->image, &impl->area, impl->extendMode, impl->matrixType, &impl->matrix); |
77 | if (BL_UNLIKELY(!newI)) |
78 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
79 | |
80 | BLInternalPatternImpl* oldI = blInternalCast(self->impl); |
81 | self->impl = newI; |
82 | return blPatternImplRelease(oldI); |
83 | } |
84 | |
85 | static BL_INLINE BLResult blPatternMakeMutable(BLPatternCore* self) noexcept { |
86 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
87 | if (!blImplIsMutable(selfI)) |
88 | return blPatternMakeMutableCopyOf(self, selfI); |
89 | else |
90 | return BL_SUCCESS; |
91 | } |
92 | |
93 | static BL_INLINE bool blPatternIsAreaValid(const BLRectI* area, int w, int h) noexcept { |
94 | if ((unsigned(area->x) <= unsigned(w)) & |
95 | (unsigned(area->y) <= unsigned(h)) & |
96 | ((unsigned(area->w) - unsigned(area->x)) <= unsigned(w)) & |
97 | ((unsigned(area->h) - unsigned(area->y)) <= unsigned(h))) |
98 | return true; |
99 | |
100 | return false; |
101 | } |
102 | |
103 | // ============================================================================ |
104 | // [BLPattern - Init / Reset] |
105 | // ============================================================================ |
106 | |
107 | BLResult blPatternInit(BLPatternCore* self) noexcept { |
108 | self->impl = &blNullPatternImpl; |
109 | return BL_SUCCESS; |
110 | } |
111 | |
112 | BLResult blPatternInitAs(BLPatternCore* self, const BLImageCore* image, const BLRectI* area, uint32_t extendMode, const BLMatrix2D* matrix) noexcept { |
113 | if (!image) |
114 | image = &BLImage::none(); |
115 | |
116 | if (!area) |
117 | area = &blPatternNoArea; |
118 | else if (BL_UNLIKELY(!blPatternIsAreaValid(area, image->impl->size.w, image->impl->size.h))) |
119 | return blTraceError(BL_ERROR_INVALID_VALUE); |
120 | |
121 | if (BL_UNLIKELY(extendMode >= BL_EXTEND_MODE_COMPLEX_COUNT)) |
122 | return blTraceError(BL_ERROR_INVALID_VALUE); |
123 | |
124 | uint32_t matrixType = BL_MATRIX2D_TYPE_IDENTITY; |
125 | if (!matrix) |
126 | matrix = &blMatrix2DIdentity; |
127 | else |
128 | matrixType = matrix->type(); |
129 | |
130 | BLInternalPatternImpl* impl = blPatternImplNew(image, area, extendMode, matrixType, matrix); |
131 | if (BL_UNLIKELY(!impl)) |
132 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
133 | |
134 | self->impl = impl; |
135 | return BL_SUCCESS; |
136 | } |
137 | |
138 | BLResult blPatternReset(BLPatternCore* self) noexcept { |
139 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
140 | self->impl = &blNullPatternImpl; |
141 | return blPatternImplRelease(selfI); |
142 | } |
143 | |
144 | // ============================================================================ |
145 | // [BLPattern - Assign / Create] |
146 | // ============================================================================ |
147 | |
148 | BLResult blPatternAssignMove(BLPatternCore* self, BLPatternCore* other) noexcept { |
149 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
150 | BLInternalPatternImpl* otherI = blInternalCast(other->impl); |
151 | |
152 | self->impl = otherI; |
153 | other->impl = &blNullPatternImpl; |
154 | |
155 | return blPatternImplRelease(selfI); |
156 | } |
157 | |
158 | BLResult blPatternAssignWeak(BLPatternCore* self, const BLPatternCore* other) noexcept { |
159 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
160 | BLInternalPatternImpl* otherI = blInternalCast(other->impl); |
161 | |
162 | self->impl = blImplIncRef(otherI); |
163 | return blPatternImplRelease(selfI); |
164 | } |
165 | |
166 | BLResult blPatternAssignDeep(BLPatternCore* self, const BLPatternCore* other) noexcept { |
167 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
168 | BLInternalPatternImpl* otherI = blInternalCast(other->impl); |
169 | |
170 | if (!blImplIsMutable(selfI)) |
171 | return blPatternMakeMutableCopyOf(self, otherI); |
172 | |
173 | selfI->patternType = 0; |
174 | selfI->extendMode = otherI->extendMode; |
175 | selfI->matrixType = otherI->matrixType; |
176 | selfI->matrix = otherI->matrix; |
177 | selfI->area = otherI->area; |
178 | return blImageAssignWeak(&selfI->image, &otherI->image); |
179 | } |
180 | |
181 | BLResult blPatternCreate(BLPatternCore* self, const BLImageCore* image, const BLRectI* area, uint32_t extendMode, const BLMatrix2D* matrix) noexcept { |
182 | if (!image) |
183 | image = &BLImage::none(); |
184 | |
185 | if (!area) |
186 | area = &blPatternNoArea; |
187 | else if (BL_UNLIKELY(!blPatternIsAreaValid(area, image->impl->size.w, image->impl->size.h))) |
188 | return blTraceError(BL_ERROR_INVALID_VALUE); |
189 | |
190 | if (BL_UNLIKELY(extendMode >= BL_EXTEND_MODE_COMPLEX_COUNT)) |
191 | return blTraceError(BL_ERROR_INVALID_VALUE); |
192 | |
193 | uint32_t matrixType = BL_MATRIX2D_TYPE_IDENTITY; |
194 | if (!matrix) |
195 | matrix = &blMatrix2DIdentity; |
196 | else |
197 | matrixType = matrix->type(); |
198 | |
199 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
200 | if (!blImplIsMutable(selfI)) { |
201 | BLInternalPatternImpl* newI = blPatternImplNew(image, area, extendMode, matrixType, matrix); |
202 | if (BL_UNLIKELY(!newI)) |
203 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
204 | |
205 | self->impl = newI; |
206 | return blPatternImplRelease(selfI); |
207 | } |
208 | else { |
209 | selfI->extendMode = uint8_t(extendMode); |
210 | selfI->matrixType = uint8_t(matrixType); |
211 | selfI->matrix = *matrix; |
212 | selfI->area = *area; |
213 | return blImageAssignWeak(&selfI->image, image); |
214 | } |
215 | } |
216 | |
217 | // ============================================================================ |
218 | // [BLPattern - Properties] |
219 | // ============================================================================ |
220 | |
221 | BLResult blPatternSetImage(BLPatternCore* self, const BLImageCore* image, const BLRectI* area) noexcept { |
222 | if (!image) |
223 | image = &BLImage::none(); |
224 | |
225 | if (!area) |
226 | area = &blPatternNoArea; |
227 | else if (!blPatternIsAreaValid(area, image->impl->size.w, image->impl->size.h)) |
228 | return blTraceError(BL_ERROR_INVALID_VALUE); |
229 | |
230 | BL_PROPAGATE(blPatternMakeMutable(self)); |
231 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
232 | |
233 | selfI->area = *area; |
234 | return blImageAssignWeak(&selfI->image, image); |
235 | } |
236 | |
237 | BLResult blPatternSetArea(BLPatternCore* self, const BLRectI* area) noexcept { |
238 | if (!area) { |
239 | area = &blPatternNoArea; |
240 | } |
241 | else { |
242 | BLImageImpl* imageImpl = self->impl->image.impl; |
243 | if (!blPatternIsAreaValid(area, imageImpl->size.w, imageImpl->size.h)) |
244 | return blTraceError(BL_ERROR_INVALID_VALUE); |
245 | } |
246 | |
247 | BL_PROPAGATE(blPatternMakeMutable(self)); |
248 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
249 | |
250 | selfI->area = *area; |
251 | return BL_SUCCESS; |
252 | } |
253 | |
254 | BLResult blPatternSetExtendMode(BLPatternCore* self, uint32_t extendMode) noexcept { |
255 | if (BL_UNLIKELY(extendMode >= BL_EXTEND_MODE_COMPLEX_COUNT)) |
256 | return blTraceError(BL_ERROR_INVALID_VALUE); |
257 | |
258 | BL_PROPAGATE(blPatternMakeMutable(self)); |
259 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
260 | |
261 | selfI->extendMode = uint8_t(extendMode); |
262 | return BL_SUCCESS; |
263 | } |
264 | |
265 | // ============================================================================ |
266 | // [BLPattern - Matrix] |
267 | // ============================================================================ |
268 | |
269 | BLResult blPatternApplyMatrixOp(BLPatternCore* self, uint32_t opType, const void* opData) noexcept { |
270 | if (BL_UNLIKELY(opType >= BL_MATRIX2D_OP_COUNT)) |
271 | return blTraceError(BL_ERROR_INVALID_VALUE); |
272 | |
273 | BLInternalPatternImpl* selfI = blInternalCast(self->impl); |
274 | if (opType == 0 && selfI->matrixType == BL_MATRIX2D_TYPE_IDENTITY) |
275 | return BL_SUCCESS; |
276 | |
277 | BL_PROPAGATE(blPatternMakeMutable(self)); |
278 | selfI = blInternalCast(self->impl); |
279 | |
280 | blMatrix2DApplyOp(&selfI->matrix, opType, opData); |
281 | selfI->matrixType = uint8_t(selfI->matrix.type()); |
282 | |
283 | return BL_SUCCESS; |
284 | } |
285 | |
286 | // ============================================================================ |
287 | // [BLPattern - Equals] |
288 | // ============================================================================ |
289 | |
290 | bool blPatternEquals(const BLPatternCore* a, const BLPatternCore* b) noexcept { |
291 | const BLPatternImpl* aI = a->impl; |
292 | const BLPatternImpl* bI = b->impl; |
293 | |
294 | if (aI == bI) |
295 | return true; |
296 | |
297 | bool eq = (aI->patternType == bI->patternType) & |
298 | (aI->extendMode == bI->extendMode ) & |
299 | (aI->matrixType == bI->matrixType ) & |
300 | (aI->matrix == bI->matrix ) & |
301 | (aI->area == bI->area ) ; |
302 | return eq && aI->image == bI->image; |
303 | } |
304 | |
305 | // ============================================================================ |
306 | // [BLPattern - Runtime Init] |
307 | // ============================================================================ |
308 | |
309 | void blPatternRtInit(BLRuntimeContext* rt) noexcept { |
310 | BL_UNUSED(rt); |
311 | |
312 | BLInternalPatternImpl* impl = &blNullPatternImpl; |
313 | blCallCtor(impl->image); |
314 | impl->implType = uint8_t(BL_IMPL_TYPE_PATTERN); |
315 | impl->implTraits = uint8_t(BL_IMPL_TRAIT_NULL); |
316 | impl->patternType = 0; |
317 | impl->extendMode = uint8_t(BL_EXTEND_MODE_REPEAT); |
318 | impl->matrix.reset(); |
319 | impl->area.reset(0, 0, 0, 0); |
320 | blAssignBuiltInNull(impl); |
321 | |
322 | // Checks whether the initialization order is correct. |
323 | BL_ASSERT(impl->image.impl != nullptr); |
324 | } |
325 | |