1 | /**************************************************************************** |
2 | * |
3 | * ftgloadr.c |
4 | * |
5 | * The FreeType glyph loader (body). |
6 | * |
7 | * Copyright (C) 2002-2019 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 <ft2build.h> |
20 | #include FT_INTERNAL_DEBUG_H |
21 | #include FT_INTERNAL_GLYPH_LOADER_H |
22 | #include FT_INTERNAL_MEMORY_H |
23 | #include FT_INTERNAL_OBJECTS_H |
24 | |
25 | #undef FT_COMPONENT |
26 | #define FT_COMPONENT gloader |
27 | |
28 | |
29 | /*************************************************************************/ |
30 | /*************************************************************************/ |
31 | /*************************************************************************/ |
32 | /***** *****/ |
33 | /***** *****/ |
34 | /***** G L Y P H L O A D E R *****/ |
35 | /***** *****/ |
36 | /***** *****/ |
37 | /*************************************************************************/ |
38 | /*************************************************************************/ |
39 | /*************************************************************************/ |
40 | |
41 | /************************************************************************** |
42 | * |
43 | * The glyph loader is a simple object which is used to load a set of |
44 | * glyphs easily. It is critical for the correct loading of composites. |
45 | * |
46 | * Ideally, one can see it as a stack of abstract `glyph' objects. |
47 | * |
48 | * loader.base Is really the bottom of the stack. It describes a |
49 | * single glyph image made of the juxtaposition of |
50 | * several glyphs (those `in the stack'). |
51 | * |
52 | * loader.current Describes the top of the stack, on which a new |
53 | * glyph can be loaded. |
54 | * |
55 | * Rewind Clears the stack. |
56 | * Prepare Set up `loader.current' for addition of a new glyph |
57 | * image. |
58 | * Add Add the `current' glyph image to the `base' one, |
59 | * and prepare for another one. |
60 | * |
61 | * The glyph loader is now a base object. Each driver used to |
62 | * re-implement it in one way or the other, which wasted code and |
63 | * energy. |
64 | * |
65 | */ |
66 | |
67 | |
68 | /* create a new glyph loader */ |
69 | FT_BASE_DEF( FT_Error ) |
70 | FT_GlyphLoader_New( FT_Memory memory, |
71 | FT_GlyphLoader *aloader ) |
72 | { |
73 | FT_GlyphLoader loader = NULL; |
74 | FT_Error error; |
75 | |
76 | |
77 | if ( !FT_NEW( loader ) ) |
78 | { |
79 | loader->memory = memory; |
80 | *aloader = loader; |
81 | } |
82 | return error; |
83 | } |
84 | |
85 | |
86 | /* rewind the glyph loader - reset counters to 0 */ |
87 | FT_BASE_DEF( void ) |
88 | FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) |
89 | { |
90 | FT_GlyphLoad base = &loader->base; |
91 | FT_GlyphLoad current = &loader->current; |
92 | |
93 | |
94 | base->outline.n_points = 0; |
95 | base->outline.n_contours = 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 = base->points + base->n_points; |
150 | current->tags = base->tags + base->n_points; |
151 | current->contours = 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 ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) |
173 | { |
174 | loader->use_extra = 1; |
175 | loader->base.extra_points2 = loader->base.extra_points + |
176 | loader->max_points; |
177 | |
178 | FT_GlyphLoader_Adjust_Points( loader ); |
179 | } |
180 | return error; |
181 | } |
182 | |
183 | |
184 | /* re-adjust the `current' subglyphs field */ |
185 | static void |
186 | FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) |
187 | { |
188 | FT_GlyphLoad base = &loader->base; |
189 | FT_GlyphLoad current = &loader->current; |
190 | |
191 | |
192 | current->subglyphs = base->subglyphs + base->num_subglyphs; |
193 | } |
194 | |
195 | |
196 | /* Ensure that we can add `n_points' and `n_contours' to our glyph. */ |
197 | /* This function reallocates its outline tables if necessary. Note that */ |
198 | /* it DOESN'T change the number of points within the loader! */ |
199 | /* */ |
200 | FT_BASE_DEF( FT_Error ) |
201 | FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, |
202 | FT_UInt n_points, |
203 | FT_UInt n_contours ) |
204 | { |
205 | FT_Memory memory = loader->memory; |
206 | FT_Error error = FT_Err_Ok; |
207 | FT_Outline* base = &loader->base.outline; |
208 | FT_Outline* current = &loader->current.outline; |
209 | FT_Bool adjust = 0; |
210 | |
211 | FT_UInt new_max, old_max; |
212 | |
213 | |
214 | /* check points & tags */ |
215 | new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + |
216 | n_points; |
217 | old_max = loader->max_points; |
218 | |
219 | if ( new_max > old_max ) |
220 | { |
221 | new_max = FT_PAD_CEIL( new_max, 8 ); |
222 | |
223 | if ( new_max > FT_OUTLINE_POINTS_MAX ) |
224 | return FT_THROW( Array_Too_Large ); |
225 | |
226 | if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || |
227 | FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) |
228 | goto Exit; |
229 | |
230 | if ( loader->use_extra ) |
231 | { |
232 | if ( FT_RENEW_ARRAY( loader->base.extra_points, |
233 | old_max * 2, new_max * 2 ) ) |
234 | goto Exit; |
235 | |
236 | FT_ARRAY_MOVE( loader->base.extra_points + new_max, |
237 | loader->base.extra_points + old_max, |
238 | old_max ); |
239 | |
240 | loader->base.extra_points2 = loader->base.extra_points + new_max; |
241 | } |
242 | |
243 | adjust = 1; |
244 | loader->max_points = new_max; |
245 | } |
246 | |
247 | /* check contours */ |
248 | old_max = loader->max_contours; |
249 | new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + |
250 | n_contours; |
251 | if ( new_max > old_max ) |
252 | { |
253 | new_max = FT_PAD_CEIL( new_max, 4 ); |
254 | |
255 | if ( new_max > FT_OUTLINE_CONTOURS_MAX ) |
256 | return FT_THROW( Array_Too_Large ); |
257 | |
258 | if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) |
259 | goto Exit; |
260 | |
261 | adjust = 1; |
262 | loader->max_contours = new_max; |
263 | } |
264 | |
265 | if ( adjust ) |
266 | FT_GlyphLoader_Adjust_Points( loader ); |
267 | |
268 | Exit: |
269 | if ( error ) |
270 | FT_GlyphLoader_Reset( loader ); |
271 | |
272 | return error; |
273 | } |
274 | |
275 | |
276 | /* Ensure that we can add `n_subglyphs' to our glyph. this function */ |
277 | /* reallocates its subglyphs table if necessary. Note that it DOES */ |
278 | /* NOT change the number of subglyphs within the loader! */ |
279 | /* */ |
280 | FT_BASE_DEF( FT_Error ) |
281 | FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, |
282 | FT_UInt n_subs ) |
283 | { |
284 | FT_Memory memory = loader->memory; |
285 | FT_Error error = FT_Err_Ok; |
286 | FT_UInt new_max, old_max; |
287 | |
288 | FT_GlyphLoad base = &loader->base; |
289 | FT_GlyphLoad current = &loader->current; |
290 | |
291 | |
292 | new_max = base->num_subglyphs + current->num_subglyphs + n_subs; |
293 | old_max = loader->max_subglyphs; |
294 | if ( new_max > old_max ) |
295 | { |
296 | new_max = FT_PAD_CEIL( new_max, 2 ); |
297 | if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) |
298 | goto Exit; |
299 | |
300 | loader->max_subglyphs = new_max; |
301 | |
302 | FT_GlyphLoader_Adjust_Subglyphs( loader ); |
303 | } |
304 | |
305 | Exit: |
306 | return error; |
307 | } |
308 | |
309 | |
310 | /* prepare loader for the addition of a new glyph on top of the base one */ |
311 | FT_BASE_DEF( void ) |
312 | FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) |
313 | { |
314 | FT_GlyphLoad current = &loader->current; |
315 | |
316 | |
317 | current->outline.n_points = 0; |
318 | current->outline.n_contours = 0; |
319 | current->num_subglyphs = 0; |
320 | |
321 | FT_GlyphLoader_Adjust_Points ( loader ); |
322 | FT_GlyphLoader_Adjust_Subglyphs( loader ); |
323 | } |
324 | |
325 | |
326 | /* add current glyph to the base image -- and prepare for another */ |
327 | FT_BASE_DEF( void ) |
328 | FT_GlyphLoader_Add( FT_GlyphLoader loader ) |
329 | { |
330 | FT_GlyphLoad base; |
331 | FT_GlyphLoad current; |
332 | |
333 | FT_Int n_curr_contours; |
334 | FT_Int n_base_points; |
335 | FT_Int n; |
336 | |
337 | |
338 | if ( !loader ) |
339 | return; |
340 | |
341 | base = &loader->base; |
342 | current = &loader->current; |
343 | |
344 | n_curr_contours = current->outline.n_contours; |
345 | n_base_points = base->outline.n_points; |
346 | |
347 | base->outline.n_points = |
348 | (short)( base->outline.n_points + current->outline.n_points ); |
349 | base->outline.n_contours = |
350 | (short)( base->outline.n_contours + current->outline.n_contours ); |
351 | |
352 | base->num_subglyphs += current->num_subglyphs; |
353 | |
354 | /* adjust contours count in newest outline */ |
355 | for ( n = 0; n < n_curr_contours; n++ ) |
356 | current->outline.contours[n] = |
357 | (short)( current->outline.contours[n] + n_base_points ); |
358 | |
359 | /* prepare for another new glyph image */ |
360 | FT_GlyphLoader_Prepare( loader ); |
361 | } |
362 | |
363 | |
364 | /* END */ |
365 | |