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_CreateExtra( 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