1 | /**************************************************************************** |
2 | * |
3 | * ftgloadr.c |
4 | * |
5 | * The FreeType glyph loader (body). |
6 | * |
7 | * Copyright (C) 2002-2023 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg |
9 | * |
10 | * This file is part of the FreeType project, and may only be used, |
11 | * modified, and distributed under the terms of the FreeType project |
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 | * this file you indicate that you have read the license and |
14 | * understand and accept it fully. |
15 | * |
16 | */ |
17 | |
18 | |
19 | #include <freetype/internal/ftdebug.h> |
20 | #include <freetype/internal/ftgloadr.h> |
21 | #include <freetype/internal/ftmemory.h> |
22 | #include <freetype/internal/ftobjs.h> |
23 | |
24 | #undef FT_COMPONENT |
25 | #define FT_COMPONENT gloader |
26 | |
27 | |
28 | /*************************************************************************/ |
29 | /*************************************************************************/ |
30 | /*************************************************************************/ |
31 | /***** *****/ |
32 | /***** *****/ |
33 | /***** G L Y P H L O A D E R *****/ |
34 | /***** *****/ |
35 | /***** *****/ |
36 | /*************************************************************************/ |
37 | /*************************************************************************/ |
38 | /*************************************************************************/ |
39 | |
40 | /************************************************************************** |
41 | * |
42 | * The glyph loader is a simple object which is used to load a set of |
43 | * glyphs easily. It is critical for the correct loading of composites. |
44 | * |
45 | * Ideally, one can see it as a stack of abstract `glyph' objects. |
46 | * |
47 | * loader.base Is really the bottom of the stack. It describes a |
48 | * single glyph image made of the juxtaposition of |
49 | * several glyphs (those `in the stack'). |
50 | * |
51 | * loader.current Describes the top of the stack, on which a new |
52 | * glyph can be loaded. |
53 | * |
54 | * Rewind Clears the stack. |
55 | * Prepare Set up `loader.current' for addition of a new glyph |
56 | * image. |
57 | * Add Add the `current' glyph image to the `base' one, |
58 | * and prepare for another one. |
59 | * |
60 | * The glyph loader is now a base object. Each driver used to |
61 | * re-implement it in one way or the other, which wasted code and |
62 | * energy. |
63 | * |
64 | */ |
65 | |
66 | |
67 | /* create a new glyph loader */ |
68 | FT_BASE_DEF( FT_Error ) |
69 | FT_GlyphLoader_New( FT_Memory memory, |
70 | FT_GlyphLoader *aloader ) |
71 | { |
72 | FT_GlyphLoader loader = NULL; |
73 | FT_Error error; |
74 | |
75 | |
76 | if ( !FT_NEW( loader ) ) |
77 | { |
78 | loader->memory = memory; |
79 | *aloader = loader; |
80 | } |
81 | return error; |
82 | } |
83 | |
84 | |
85 | /* rewind the glyph loader - reset counters to 0 */ |
86 | FT_BASE_DEF( void ) |
87 | FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) |
88 | { |
89 | FT_GlyphLoad base = &loader->base; |
90 | FT_GlyphLoad current = &loader->current; |
91 | |
92 | |
93 | base->outline.n_points = 0; |
94 | base->outline.n_contours = 0; |
95 | base->outline.flags = 0; |
96 | base->num_subglyphs = 0; |
97 | |
98 | *current = *base; |
99 | } |
100 | |
101 | |
102 | /* reset glyph loader, free all allocated tables, */ |
103 | /* and start from zero */ |
104 | FT_BASE_DEF( void ) |
105 | FT_GlyphLoader_Reset( FT_GlyphLoader loader ) |
106 | { |
107 | FT_Memory memory = loader->memory; |
108 | |
109 | |
110 | FT_FREE( loader->base.outline.points ); |
111 | FT_FREE( loader->base.outline.tags ); |
112 | FT_FREE( loader->base.outline.contours ); |
113 | FT_FREE( loader->base.extra_points ); |
114 | FT_FREE( loader->base.subglyphs ); |
115 | |
116 | loader->base.extra_points2 = NULL; |
117 | |
118 | loader->max_points = 0; |
119 | loader->max_contours = 0; |
120 | loader->max_subglyphs = 0; |
121 | |
122 | FT_GlyphLoader_Rewind( loader ); |
123 | } |
124 | |
125 | |
126 | /* delete a glyph loader */ |
127 | FT_BASE_DEF( void ) |
128 | FT_GlyphLoader_Done( FT_GlyphLoader loader ) |
129 | { |
130 | if ( loader ) |
131 | { |
132 | FT_Memory memory = loader->memory; |
133 | |
134 | |
135 | FT_GlyphLoader_Reset( loader ); |
136 | FT_FREE( loader ); |
137 | } |
138 | } |
139 | |
140 | |
141 | /* re-adjust the `current' outline fields */ |
142 | static void |
143 | FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) |
144 | { |
145 | FT_Outline* base = &loader->base.outline; |
146 | FT_Outline* current = &loader->current.outline; |
147 | |
148 | |
149 | current->points = FT_OFFSET( base->points, base->n_points ); |
150 | current->tags = FT_OFFSET( base->tags, base->n_points ); |
151 | current->contours = FT_OFFSET( base->contours, base->n_contours ); |
152 | |
153 | /* handle extra points table - if any */ |
154 | if ( loader->use_extra ) |
155 | { |
156 | loader->current.extra_points = loader->base.extra_points + |
157 | base->n_points; |
158 | |
159 | loader->current.extra_points2 = loader->base.extra_points2 + |
160 | base->n_points; |
161 | } |
162 | } |
163 | |
164 | |
165 | FT_BASE_DEF( FT_Error ) |
166 | ( FT_GlyphLoader loader ) |
167 | { |
168 | FT_Error error; |
169 | FT_Memory memory = loader->memory; |
170 | |
171 | |
172 | if ( loader->max_points == 0 || |
173 | loader->base.extra_points != NULL ) |
174 | return FT_Err_Ok; |
175 | |
176 | if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) |
177 | { |
178 | loader->use_extra = 1; |
179 | loader->base.extra_points2 = loader->base.extra_points + |
180 | loader->max_points; |
181 | |
182 | FT_GlyphLoader_Adjust_Points( loader ); |
183 | } |
184 | return error; |
185 | } |
186 | |
187 | |
188 | /* re-adjust the `current' subglyphs field */ |
189 | static void |
190 | FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) |
191 | { |
192 | FT_GlyphLoad base = &loader->base; |
193 | FT_GlyphLoad current = &loader->current; |
194 | |
195 | |
196 | current->subglyphs = FT_OFFSET( base->subglyphs, base->num_subglyphs ); |
197 | } |
198 | |
199 | |
200 | /* Ensure that we can add `n_points' and `n_contours' to our glyph. */ |
201 | /* This function reallocates its outline tables if necessary. Note that */ |
202 | /* it DOESN'T change the number of points within the loader! */ |
203 | /* */ |
204 | FT_BASE_DEF( FT_Error ) |
205 | FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, |
206 | FT_UInt n_points, |
207 | FT_UInt n_contours ) |
208 | { |
209 | FT_Memory memory = loader->memory; |
210 | FT_Error error = FT_Err_Ok; |
211 | FT_Outline* base = &loader->base.outline; |
212 | FT_Outline* current = &loader->current.outline; |
213 | FT_Bool adjust = 0; |
214 | |
215 | FT_UInt new_max, old_max, min_new_max; |
216 | |
217 | |
218 | error = FT_GlyphLoader_CreateExtra( loader ); |
219 | if ( error ) |
220 | goto Exit; |
221 | |
222 | /* check points & tags */ |
223 | new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + |
224 | n_points; |
225 | old_max = loader->max_points; |
226 | |
227 | if ( new_max > old_max ) |
228 | { |
229 | if ( new_max > FT_OUTLINE_POINTS_MAX ) |
230 | { |
231 | error = FT_THROW( Array_Too_Large ); |
232 | goto Exit; |
233 | } |
234 | |
235 | min_new_max = old_max + ( old_max >> 1 ); |
236 | if ( new_max < min_new_max ) |
237 | new_max = min_new_max; |
238 | new_max = FT_PAD_CEIL( new_max, 8 ); |
239 | if ( new_max > FT_OUTLINE_POINTS_MAX ) |
240 | new_max = FT_OUTLINE_POINTS_MAX; |
241 | |
242 | if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || |
243 | FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) |
244 | goto Exit; |
245 | |
246 | if ( loader->use_extra ) |
247 | { |
248 | if ( FT_RENEW_ARRAY( loader->base.extra_points, |
249 | old_max * 2, new_max * 2 ) ) |
250 | goto Exit; |
251 | |
252 | FT_ARRAY_MOVE( loader->base.extra_points + new_max, |
253 | loader->base.extra_points + old_max, |
254 | old_max ); |
255 | |
256 | loader->base.extra_points2 = loader->base.extra_points + new_max; |
257 | } |
258 | |
259 | adjust = 1; |
260 | loader->max_points = new_max; |
261 | } |
262 | |
263 | error = FT_GlyphLoader_CreateExtra( loader ); |
264 | if ( error ) |
265 | goto Exit; |
266 | |
267 | /* check contours */ |
268 | old_max = loader->max_contours; |
269 | new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + |
270 | n_contours; |
271 | if ( new_max > old_max ) |
272 | { |
273 | if ( new_max > FT_OUTLINE_CONTOURS_MAX ) |
274 | { |
275 | error = FT_THROW( Array_Too_Large ); |
276 | goto Exit; |
277 | } |
278 | |
279 | min_new_max = old_max + ( old_max >> 1 ); |
280 | if ( new_max < min_new_max ) |
281 | new_max = min_new_max; |
282 | new_max = FT_PAD_CEIL( new_max, 4 ); |
283 | if ( new_max > FT_OUTLINE_CONTOURS_MAX ) |
284 | new_max = FT_OUTLINE_CONTOURS_MAX; |
285 | |
286 | if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) |
287 | goto Exit; |
288 | |
289 | adjust = 1; |
290 | loader->max_contours = new_max; |
291 | } |
292 | |
293 | if ( adjust ) |
294 | FT_GlyphLoader_Adjust_Points( loader ); |
295 | |
296 | Exit: |
297 | if ( error ) |
298 | FT_GlyphLoader_Reset( loader ); |
299 | |
300 | return error; |
301 | } |
302 | |
303 | |
304 | /* Ensure that we can add `n_subglyphs' to our glyph. this function */ |
305 | /* reallocates its subglyphs table if necessary. Note that it DOES */ |
306 | /* NOT change the number of subglyphs within the loader! */ |
307 | /* */ |
308 | FT_BASE_DEF( FT_Error ) |
309 | FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, |
310 | FT_UInt n_subs ) |
311 | { |
312 | FT_Memory memory = loader->memory; |
313 | FT_Error error = FT_Err_Ok; |
314 | FT_UInt new_max, old_max; |
315 | |
316 | FT_GlyphLoad base = &loader->base; |
317 | FT_GlyphLoad current = &loader->current; |
318 | |
319 | |
320 | new_max = base->num_subglyphs + current->num_subglyphs + n_subs; |
321 | old_max = loader->max_subglyphs; |
322 | if ( new_max > old_max ) |
323 | { |
324 | new_max = FT_PAD_CEIL( new_max, 2 ); |
325 | if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) |
326 | goto Exit; |
327 | |
328 | loader->max_subglyphs = new_max; |
329 | |
330 | FT_GlyphLoader_Adjust_Subglyphs( loader ); |
331 | } |
332 | |
333 | Exit: |
334 | return error; |
335 | } |
336 | |
337 | |
338 | /* prepare loader for the addition of a new glyph on top of the base one */ |
339 | FT_BASE_DEF( void ) |
340 | FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) |
341 | { |
342 | FT_GlyphLoad current = &loader->current; |
343 | |
344 | |
345 | current->outline.n_points = 0; |
346 | current->outline.n_contours = 0; |
347 | current->num_subglyphs = 0; |
348 | |
349 | FT_GlyphLoader_Adjust_Points ( loader ); |
350 | FT_GlyphLoader_Adjust_Subglyphs( loader ); |
351 | } |
352 | |
353 | |
354 | /* add current glyph to the base image -- and prepare for another */ |
355 | FT_BASE_DEF( void ) |
356 | FT_GlyphLoader_Add( FT_GlyphLoader loader ) |
357 | { |
358 | FT_GlyphLoad base; |
359 | FT_GlyphLoad current; |
360 | |
361 | FT_Int n_curr_contours; |
362 | FT_Int n_base_points; |
363 | FT_Int n; |
364 | |
365 | |
366 | if ( !loader ) |
367 | return; |
368 | |
369 | base = &loader->base; |
370 | current = &loader->current; |
371 | |
372 | n_curr_contours = current->outline.n_contours; |
373 | n_base_points = base->outline.n_points; |
374 | |
375 | base->outline.n_points = |
376 | (short)( base->outline.n_points + current->outline.n_points ); |
377 | base->outline.n_contours = |
378 | (short)( base->outline.n_contours + current->outline.n_contours ); |
379 | |
380 | base->num_subglyphs += current->num_subglyphs; |
381 | |
382 | /* adjust contours count in newest outline */ |
383 | for ( n = 0; n < n_curr_contours; n++ ) |
384 | current->outline.contours[n] = |
385 | (short)( current->outline.contours[n] + n_base_points ); |
386 | |
387 | /* prepare for another new glyph image */ |
388 | FT_GlyphLoader_Prepare( loader ); |
389 | } |
390 | |
391 | |
392 | /* END */ |
393 | |