1 | /**************************************************************************** |
2 | * |
3 | * ftglyph.c |
4 | * |
5 | * FreeType convenience functions to handle glyphs (body). |
6 | * |
7 | * Copyright (C) 1996-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 | * |
20 | * This file contains the definition of several convenience functions |
21 | * that can be used by client applications to easily retrieve glyph |
22 | * bitmaps and outlines from a given face. |
23 | * |
24 | * These functions should be optional if you are writing a font server |
25 | * or text layout engine on top of FreeType. However, they are pretty |
26 | * handy for many other simple uses of the library. |
27 | * |
28 | */ |
29 | |
30 | |
31 | #include <freetype/internal/ftdebug.h> |
32 | |
33 | #include <freetype/ftglyph.h> |
34 | #include <freetype/ftoutln.h> |
35 | #include <freetype/ftbitmap.h> |
36 | #include <freetype/internal/ftobjs.h> |
37 | #include <freetype/otsvg.h> |
38 | |
39 | #include "ftbase.h" |
40 | |
41 | |
42 | /************************************************************************** |
43 | * |
44 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
45 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
46 | * messages during execution. |
47 | */ |
48 | #undef FT_COMPONENT |
49 | #define FT_COMPONENT glyph |
50 | |
51 | |
52 | /*************************************************************************/ |
53 | /*************************************************************************/ |
54 | /**** ****/ |
55 | /**** FT_BitmapGlyph support ****/ |
56 | /**** ****/ |
57 | /*************************************************************************/ |
58 | /*************************************************************************/ |
59 | |
60 | FT_CALLBACK_DEF( FT_Error ) |
61 | ft_bitmap_glyph_init( FT_Glyph bitmap_glyph, |
62 | FT_GlyphSlot slot ) |
63 | { |
64 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
65 | FT_Error error = FT_Err_Ok; |
66 | FT_Library library = FT_GLYPH( glyph )->library; |
67 | |
68 | |
69 | if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) |
70 | { |
71 | error = FT_THROW( Invalid_Glyph_Format ); |
72 | goto Exit; |
73 | } |
74 | |
75 | glyph->left = slot->bitmap_left; |
76 | glyph->top = slot->bitmap_top; |
77 | |
78 | /* do lazy copying whenever possible */ |
79 | if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) |
80 | { |
81 | glyph->bitmap = slot->bitmap; |
82 | slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; |
83 | } |
84 | else |
85 | { |
86 | FT_Bitmap_Init( &glyph->bitmap ); |
87 | error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); |
88 | } |
89 | |
90 | Exit: |
91 | return error; |
92 | } |
93 | |
94 | |
95 | FT_CALLBACK_DEF( FT_Error ) |
96 | ft_bitmap_glyph_copy( FT_Glyph bitmap_source, |
97 | FT_Glyph bitmap_target ) |
98 | { |
99 | FT_Library library = bitmap_source->library; |
100 | FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source; |
101 | FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target; |
102 | |
103 | |
104 | target->left = source->left; |
105 | target->top = source->top; |
106 | |
107 | return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); |
108 | } |
109 | |
110 | |
111 | FT_CALLBACK_DEF( void ) |
112 | ft_bitmap_glyph_done( FT_Glyph bitmap_glyph ) |
113 | { |
114 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
115 | FT_Library library = FT_GLYPH( glyph )->library; |
116 | |
117 | |
118 | FT_Bitmap_Done( library, &glyph->bitmap ); |
119 | } |
120 | |
121 | |
122 | FT_CALLBACK_DEF( void ) |
123 | ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph, |
124 | FT_BBox* cbox ) |
125 | { |
126 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
127 | |
128 | |
129 | cbox->xMin = glyph->left * 64; |
130 | cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 ); |
131 | cbox->yMax = glyph->top * 64; |
132 | cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 ); |
133 | } |
134 | |
135 | |
136 | FT_DEFINE_GLYPH( |
137 | ft_bitmap_glyph_class, |
138 | |
139 | sizeof ( FT_BitmapGlyphRec ), |
140 | FT_GLYPH_FORMAT_BITMAP, |
141 | |
142 | ft_bitmap_glyph_init, /* FT_Glyph_InitFunc glyph_init */ |
143 | ft_bitmap_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ |
144 | ft_bitmap_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ |
145 | NULL, /* FT_Glyph_TransformFunc glyph_transform */ |
146 | ft_bitmap_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ |
147 | NULL /* FT_Glyph_PrepareFunc glyph_prepare */ |
148 | ) |
149 | |
150 | |
151 | /*************************************************************************/ |
152 | /*************************************************************************/ |
153 | /**** ****/ |
154 | /**** FT_OutlineGlyph support ****/ |
155 | /**** ****/ |
156 | /*************************************************************************/ |
157 | /*************************************************************************/ |
158 | |
159 | |
160 | FT_CALLBACK_DEF( FT_Error ) |
161 | ft_outline_glyph_init( FT_Glyph outline_glyph, |
162 | FT_GlyphSlot slot ) |
163 | { |
164 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
165 | FT_Error error = FT_Err_Ok; |
166 | FT_Library library = FT_GLYPH( glyph )->library; |
167 | FT_Outline* source = &slot->outline; |
168 | FT_Outline* target = &glyph->outline; |
169 | |
170 | |
171 | /* check format in glyph slot */ |
172 | if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) |
173 | { |
174 | error = FT_THROW( Invalid_Glyph_Format ); |
175 | goto Exit; |
176 | } |
177 | |
178 | /* allocate new outline */ |
179 | error = FT_Outline_New( library, |
180 | (FT_UInt)source->n_points, |
181 | source->n_contours, |
182 | &glyph->outline ); |
183 | if ( error ) |
184 | goto Exit; |
185 | |
186 | FT_Outline_Copy( source, target ); |
187 | |
188 | Exit: |
189 | return error; |
190 | } |
191 | |
192 | |
193 | FT_CALLBACK_DEF( void ) |
194 | ft_outline_glyph_done( FT_Glyph outline_glyph ) |
195 | { |
196 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
197 | |
198 | |
199 | FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); |
200 | } |
201 | |
202 | |
203 | FT_CALLBACK_DEF( FT_Error ) |
204 | ft_outline_glyph_copy( FT_Glyph outline_source, |
205 | FT_Glyph outline_target ) |
206 | { |
207 | FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source; |
208 | FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target; |
209 | FT_Error error; |
210 | FT_Library library = FT_GLYPH( source )->library; |
211 | |
212 | |
213 | error = FT_Outline_New( library, |
214 | (FT_UInt)source->outline.n_points, |
215 | source->outline.n_contours, |
216 | &target->outline ); |
217 | if ( !error ) |
218 | FT_Outline_Copy( &source->outline, &target->outline ); |
219 | |
220 | return error; |
221 | } |
222 | |
223 | |
224 | FT_CALLBACK_DEF( void ) |
225 | ft_outline_glyph_transform( FT_Glyph outline_glyph, |
226 | const FT_Matrix* matrix, |
227 | const FT_Vector* delta ) |
228 | { |
229 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
230 | |
231 | |
232 | if ( matrix ) |
233 | FT_Outline_Transform( &glyph->outline, matrix ); |
234 | |
235 | if ( delta ) |
236 | FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); |
237 | } |
238 | |
239 | |
240 | FT_CALLBACK_DEF( void ) |
241 | ft_outline_glyph_bbox( FT_Glyph outline_glyph, |
242 | FT_BBox* bbox ) |
243 | { |
244 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
245 | |
246 | |
247 | FT_Outline_Get_CBox( &glyph->outline, bbox ); |
248 | } |
249 | |
250 | |
251 | FT_CALLBACK_DEF( FT_Error ) |
252 | ft_outline_glyph_prepare( FT_Glyph outline_glyph, |
253 | FT_GlyphSlot slot ) |
254 | { |
255 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
256 | |
257 | |
258 | slot->format = FT_GLYPH_FORMAT_OUTLINE; |
259 | slot->outline = glyph->outline; |
260 | slot->outline.flags &= ~FT_OUTLINE_OWNER; |
261 | |
262 | return FT_Err_Ok; |
263 | } |
264 | |
265 | |
266 | FT_DEFINE_GLYPH( |
267 | ft_outline_glyph_class, |
268 | |
269 | sizeof ( FT_OutlineGlyphRec ), |
270 | FT_GLYPH_FORMAT_OUTLINE, |
271 | |
272 | ft_outline_glyph_init, /* FT_Glyph_InitFunc glyph_init */ |
273 | ft_outline_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ |
274 | ft_outline_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ |
275 | ft_outline_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ |
276 | ft_outline_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ |
277 | ft_outline_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ |
278 | ) |
279 | |
280 | |
281 | #ifdef FT_CONFIG_OPTION_SVG |
282 | |
283 | /*************************************************************************/ |
284 | /*************************************************************************/ |
285 | /**** ****/ |
286 | /**** FT_SvgGlyph support ****/ |
287 | /**** ****/ |
288 | /*************************************************************************/ |
289 | /*************************************************************************/ |
290 | |
291 | |
292 | FT_CALLBACK_DEF( FT_Error ) |
293 | ft_svg_glyph_init( FT_Glyph svg_glyph, |
294 | FT_GlyphSlot slot ) |
295 | { |
296 | FT_ULong doc_length; |
297 | FT_SVG_Document document; |
298 | FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; |
299 | |
300 | FT_Error error = FT_Err_Ok; |
301 | FT_Memory memory = FT_GLYPH( glyph )->library->memory; |
302 | |
303 | |
304 | if ( slot->format != FT_GLYPH_FORMAT_SVG ) |
305 | { |
306 | error = FT_THROW( Invalid_Glyph_Format ); |
307 | goto Exit; |
308 | } |
309 | |
310 | if ( slot->other == NULL ) |
311 | { |
312 | error = FT_THROW( Invalid_Slot_Handle ); |
313 | goto Exit; |
314 | } |
315 | |
316 | document = (FT_SVG_Document)slot->other; |
317 | |
318 | if ( document->svg_document_length == 0 ) |
319 | { |
320 | error = FT_THROW( Invalid_Slot_Handle ); |
321 | goto Exit; |
322 | } |
323 | |
324 | /* allocate a new document */ |
325 | doc_length = document->svg_document_length; |
326 | if ( FT_QALLOC( glyph->svg_document, doc_length ) ) |
327 | goto Exit; |
328 | glyph->svg_document_length = doc_length; |
329 | |
330 | glyph->glyph_index = slot->glyph_index; |
331 | |
332 | glyph->metrics = document->metrics; |
333 | glyph->units_per_EM = document->units_per_EM; |
334 | |
335 | glyph->start_glyph_id = document->start_glyph_id; |
336 | glyph->end_glyph_id = document->end_glyph_id; |
337 | |
338 | glyph->transform = document->transform; |
339 | glyph->delta = document->delta; |
340 | |
341 | /* copy the document into glyph */ |
342 | FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); |
343 | |
344 | Exit: |
345 | return error; |
346 | } |
347 | |
348 | |
349 | FT_CALLBACK_DEF( void ) |
350 | ft_svg_glyph_done( FT_Glyph svg_glyph ) |
351 | { |
352 | FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; |
353 | FT_Memory memory = svg_glyph->library->memory; |
354 | |
355 | |
356 | /* just free the memory */ |
357 | FT_FREE( glyph->svg_document ); |
358 | } |
359 | |
360 | |
361 | FT_CALLBACK_DEF( FT_Error ) |
362 | ft_svg_glyph_copy( FT_Glyph svg_source, |
363 | FT_Glyph svg_target ) |
364 | { |
365 | FT_SvgGlyph source = (FT_SvgGlyph)svg_source; |
366 | FT_SvgGlyph target = (FT_SvgGlyph)svg_target; |
367 | |
368 | FT_Error error = FT_Err_Ok; |
369 | FT_Memory memory = FT_GLYPH( source )->library->memory; |
370 | |
371 | |
372 | if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) |
373 | { |
374 | error = FT_THROW( Invalid_Glyph_Format ); |
375 | goto Exit; |
376 | } |
377 | |
378 | if ( source->svg_document_length == 0 ) |
379 | { |
380 | error = FT_THROW( Invalid_Slot_Handle ); |
381 | goto Exit; |
382 | } |
383 | |
384 | target->glyph_index = source->glyph_index; |
385 | |
386 | target->svg_document_length = source->svg_document_length; |
387 | |
388 | target->metrics = source->metrics; |
389 | target->units_per_EM = source->units_per_EM; |
390 | |
391 | target->start_glyph_id = source->start_glyph_id; |
392 | target->end_glyph_id = source->end_glyph_id; |
393 | |
394 | target->transform = source->transform; |
395 | target->delta = source->delta; |
396 | |
397 | /* allocate space for the SVG document */ |
398 | if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) |
399 | goto Exit; |
400 | |
401 | /* copy the document */ |
402 | FT_MEM_COPY( target->svg_document, |
403 | source->svg_document, |
404 | target->svg_document_length ); |
405 | |
406 | Exit: |
407 | return error; |
408 | } |
409 | |
410 | |
411 | FT_CALLBACK_DEF( void ) |
412 | ft_svg_glyph_transform( FT_Glyph svg_glyph, |
413 | const FT_Matrix* _matrix, |
414 | const FT_Vector* _delta ) |
415 | { |
416 | FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; |
417 | FT_Matrix* matrix = (FT_Matrix*)_matrix; |
418 | FT_Vector* delta = (FT_Vector*)_delta; |
419 | |
420 | FT_Matrix tmp_matrix; |
421 | FT_Vector tmp_delta; |
422 | |
423 | FT_Matrix a, b; |
424 | FT_Pos x, y; |
425 | |
426 | |
427 | if ( !matrix ) |
428 | { |
429 | tmp_matrix.xx = 0x10000; |
430 | tmp_matrix.xy = 0; |
431 | tmp_matrix.yx = 0; |
432 | tmp_matrix.yy = 0x10000; |
433 | |
434 | matrix = &tmp_matrix; |
435 | } |
436 | |
437 | if ( !delta ) |
438 | { |
439 | tmp_delta.x = 0; |
440 | tmp_delta.y = 0; |
441 | |
442 | delta = &tmp_delta; |
443 | } |
444 | |
445 | a = glyph->transform; |
446 | b = *matrix; |
447 | FT_Matrix_Multiply( &b, &a ); |
448 | |
449 | x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), |
450 | FT_MulFix( matrix->xy, glyph->delta.y ) ), |
451 | delta->x ); |
452 | y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), |
453 | FT_MulFix( matrix->yy, glyph->delta.y ) ), |
454 | delta->y ); |
455 | |
456 | glyph->delta.x = x; |
457 | glyph->delta.y = y; |
458 | |
459 | glyph->transform = a; |
460 | } |
461 | |
462 | |
463 | FT_CALLBACK_DEF( FT_Error ) |
464 | ft_svg_glyph_prepare( FT_Glyph svg_glyph, |
465 | FT_GlyphSlot slot ) |
466 | { |
467 | FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; |
468 | |
469 | FT_Error error = FT_Err_Ok; |
470 | FT_Memory memory = svg_glyph->library->memory; |
471 | |
472 | FT_SVG_Document document = NULL; |
473 | |
474 | |
475 | if ( FT_NEW( document ) ) |
476 | return error; |
477 | |
478 | document->svg_document = glyph->svg_document; |
479 | document->svg_document_length = glyph->svg_document_length; |
480 | |
481 | document->metrics = glyph->metrics; |
482 | document->units_per_EM = glyph->units_per_EM; |
483 | |
484 | document->start_glyph_id = glyph->start_glyph_id; |
485 | document->end_glyph_id = glyph->end_glyph_id; |
486 | |
487 | document->transform = glyph->transform; |
488 | document->delta = glyph->delta; |
489 | |
490 | slot->format = FT_GLYPH_FORMAT_SVG; |
491 | slot->glyph_index = glyph->glyph_index; |
492 | slot->other = document; |
493 | |
494 | return error; |
495 | } |
496 | |
497 | |
498 | FT_DEFINE_GLYPH( |
499 | ft_svg_glyph_class, |
500 | |
501 | sizeof ( FT_SvgGlyphRec ), |
502 | FT_GLYPH_FORMAT_SVG, |
503 | |
504 | ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */ |
505 | ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ |
506 | ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ |
507 | ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ |
508 | NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ |
509 | ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ |
510 | ) |
511 | |
512 | #endif /* FT_CONFIG_OPTION_SVG */ |
513 | |
514 | |
515 | /*************************************************************************/ |
516 | /*************************************************************************/ |
517 | /**** ****/ |
518 | /**** FT_Glyph class and API ****/ |
519 | /**** ****/ |
520 | /*************************************************************************/ |
521 | /*************************************************************************/ |
522 | |
523 | static FT_Error |
524 | ft_new_glyph( FT_Library library, |
525 | const FT_Glyph_Class* clazz, |
526 | FT_Glyph* aglyph ) |
527 | { |
528 | FT_Memory memory = library->memory; |
529 | FT_Error error; |
530 | FT_Glyph glyph = NULL; |
531 | |
532 | |
533 | *aglyph = NULL; |
534 | |
535 | if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) |
536 | { |
537 | glyph->library = library; |
538 | glyph->clazz = clazz; |
539 | glyph->format = clazz->glyph_format; |
540 | |
541 | *aglyph = glyph; |
542 | } |
543 | |
544 | return error; |
545 | } |
546 | |
547 | |
548 | /* documentation is in ftglyph.h */ |
549 | |
550 | FT_EXPORT_DEF( FT_Error ) |
551 | FT_Glyph_Copy( FT_Glyph source, |
552 | FT_Glyph *target ) |
553 | { |
554 | FT_Glyph copy; |
555 | FT_Error error; |
556 | const FT_Glyph_Class* clazz; |
557 | |
558 | |
559 | /* check arguments */ |
560 | if ( !target || !source || !source->clazz ) |
561 | { |
562 | error = FT_THROW( Invalid_Argument ); |
563 | goto Exit; |
564 | } |
565 | |
566 | *target = NULL; |
567 | |
568 | if ( !source || !source->clazz ) |
569 | { |
570 | error = FT_THROW( Invalid_Argument ); |
571 | goto Exit; |
572 | } |
573 | |
574 | clazz = source->clazz; |
575 | error = ft_new_glyph( source->library, clazz, © ); |
576 | if ( error ) |
577 | goto Exit; |
578 | |
579 | copy->advance = source->advance; |
580 | copy->format = source->format; |
581 | |
582 | if ( clazz->glyph_copy ) |
583 | error = clazz->glyph_copy( source, copy ); |
584 | |
585 | if ( error ) |
586 | FT_Done_Glyph( copy ); |
587 | else |
588 | *target = copy; |
589 | |
590 | Exit: |
591 | return error; |
592 | } |
593 | |
594 | |
595 | /* documentation is in ftglyph.h */ |
596 | |
597 | FT_EXPORT( FT_Error ) |
598 | FT_New_Glyph( FT_Library library, |
599 | FT_Glyph_Format format, |
600 | FT_Glyph *aglyph ) |
601 | { |
602 | const FT_Glyph_Class* clazz = NULL; |
603 | |
604 | if ( !library || !aglyph ) |
605 | return FT_THROW( Invalid_Argument ); |
606 | |
607 | /* if it is a bitmap, that's easy :-) */ |
608 | if ( format == FT_GLYPH_FORMAT_BITMAP ) |
609 | clazz = &ft_bitmap_glyph_class; |
610 | |
611 | /* if it is an outline */ |
612 | else if ( format == FT_GLYPH_FORMAT_OUTLINE ) |
613 | clazz = &ft_outline_glyph_class; |
614 | |
615 | #ifdef FT_CONFIG_OPTION_SVG |
616 | /* if it is an SVG glyph */ |
617 | else if ( format == FT_GLYPH_FORMAT_SVG ) |
618 | clazz = &ft_svg_glyph_class; |
619 | #endif |
620 | |
621 | else |
622 | { |
623 | /* try to find a renderer that supports the glyph image format */ |
624 | FT_Renderer render = FT_Lookup_Renderer( library, format, 0 ); |
625 | |
626 | |
627 | if ( render ) |
628 | clazz = &render->glyph_class; |
629 | } |
630 | |
631 | if ( !clazz ) |
632 | return FT_THROW( Invalid_Glyph_Format ); |
633 | |
634 | /* create FT_Glyph object */ |
635 | return ft_new_glyph( library, clazz, aglyph ); |
636 | } |
637 | |
638 | |
639 | /* documentation is in ftglyph.h */ |
640 | |
641 | FT_EXPORT_DEF( FT_Error ) |
642 | FT_Get_Glyph( FT_GlyphSlot slot, |
643 | FT_Glyph *aglyph ) |
644 | { |
645 | FT_Error error; |
646 | FT_Glyph glyph; |
647 | |
648 | |
649 | if ( !slot ) |
650 | return FT_THROW( Invalid_Slot_Handle ); |
651 | |
652 | if ( !aglyph ) |
653 | return FT_THROW( Invalid_Argument ); |
654 | |
655 | /* create FT_Glyph object */ |
656 | error = FT_New_Glyph( slot->library, slot->format, &glyph ); |
657 | if ( error ) |
658 | goto Exit; |
659 | |
660 | /* copy advance while converting 26.6 to 16.16 format */ |
661 | if ( slot->advance.x >= 0x8000L * 64 || |
662 | slot->advance.x <= -0x8000L * 64 ) |
663 | { |
664 | FT_ERROR(( "FT_Get_Glyph: advance width too large\n" )); |
665 | error = FT_THROW( Invalid_Argument ); |
666 | goto Exit2; |
667 | } |
668 | if ( slot->advance.y >= 0x8000L * 64 || |
669 | slot->advance.y <= -0x8000L * 64 ) |
670 | { |
671 | FT_ERROR(( "FT_Get_Glyph: advance height too large\n" )); |
672 | error = FT_THROW( Invalid_Argument ); |
673 | goto Exit2; |
674 | } |
675 | |
676 | glyph->advance.x = slot->advance.x * 1024; |
677 | glyph->advance.y = slot->advance.y * 1024; |
678 | |
679 | /* now import the image from the glyph slot */ |
680 | error = glyph->clazz->glyph_init( glyph, slot ); |
681 | |
682 | Exit2: |
683 | /* if an error occurred, destroy the glyph */ |
684 | if ( error ) |
685 | { |
686 | FT_Done_Glyph( glyph ); |
687 | *aglyph = NULL; |
688 | } |
689 | else |
690 | *aglyph = glyph; |
691 | |
692 | Exit: |
693 | return error; |
694 | } |
695 | |
696 | |
697 | /* documentation is in ftglyph.h */ |
698 | |
699 | FT_EXPORT_DEF( FT_Error ) |
700 | FT_Glyph_Transform( FT_Glyph glyph, |
701 | const FT_Matrix* matrix, |
702 | const FT_Vector* delta ) |
703 | { |
704 | FT_Error error = FT_Err_Ok; |
705 | |
706 | |
707 | if ( !glyph || !glyph->clazz ) |
708 | error = FT_THROW( Invalid_Argument ); |
709 | else |
710 | { |
711 | const FT_Glyph_Class* clazz = glyph->clazz; |
712 | |
713 | |
714 | if ( clazz->glyph_transform ) |
715 | { |
716 | /* transform glyph image */ |
717 | clazz->glyph_transform( glyph, matrix, delta ); |
718 | |
719 | /* transform advance vector */ |
720 | if ( matrix ) |
721 | FT_Vector_Transform( &glyph->advance, matrix ); |
722 | } |
723 | else |
724 | error = FT_THROW( Invalid_Glyph_Format ); |
725 | } |
726 | return error; |
727 | } |
728 | |
729 | |
730 | /* documentation is in ftglyph.h */ |
731 | |
732 | FT_EXPORT_DEF( void ) |
733 | FT_Glyph_Get_CBox( FT_Glyph glyph, |
734 | FT_UInt bbox_mode, |
735 | FT_BBox *acbox ) |
736 | { |
737 | const FT_Glyph_Class* clazz; |
738 | |
739 | |
740 | if ( !acbox ) |
741 | return; |
742 | |
743 | acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; |
744 | |
745 | if ( !glyph || !glyph->clazz ) |
746 | return; |
747 | |
748 | clazz = glyph->clazz; |
749 | if ( !clazz->glyph_bbox ) |
750 | return; |
751 | |
752 | /* retrieve bbox in 26.6 coordinates */ |
753 | clazz->glyph_bbox( glyph, acbox ); |
754 | |
755 | /* perform grid fitting if needed */ |
756 | if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || |
757 | bbox_mode == FT_GLYPH_BBOX_PIXELS ) |
758 | { |
759 | acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); |
760 | acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); |
761 | acbox->xMax = FT_PIX_CEIL_LONG( acbox->xMax ); |
762 | acbox->yMax = FT_PIX_CEIL_LONG( acbox->yMax ); |
763 | } |
764 | |
765 | /* convert to integer pixels if needed */ |
766 | if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || |
767 | bbox_mode == FT_GLYPH_BBOX_PIXELS ) |
768 | { |
769 | acbox->xMin >>= 6; |
770 | acbox->yMin >>= 6; |
771 | acbox->xMax >>= 6; |
772 | acbox->yMax >>= 6; |
773 | } |
774 | } |
775 | |
776 | |
777 | /* documentation is in ftglyph.h */ |
778 | |
779 | FT_EXPORT_DEF( FT_Error ) |
780 | FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, |
781 | FT_Render_Mode render_mode, |
782 | const FT_Vector* origin, |
783 | FT_Bool destroy ) |
784 | { |
785 | FT_GlyphSlotRec dummy; |
786 | FT_GlyphSlot_InternalRec dummy_internal; |
787 | FT_Error error = FT_Err_Ok; |
788 | FT_Glyph b, glyph; |
789 | FT_BitmapGlyph bitmap = NULL; |
790 | const FT_Glyph_Class* clazz; |
791 | |
792 | FT_Library library; |
793 | |
794 | |
795 | /* check argument */ |
796 | if ( !the_glyph ) |
797 | goto Bad; |
798 | glyph = *the_glyph; |
799 | if ( !glyph ) |
800 | goto Bad; |
801 | |
802 | clazz = glyph->clazz; |
803 | library = glyph->library; |
804 | if ( !library || !clazz ) |
805 | goto Bad; |
806 | |
807 | /* when called with a bitmap glyph, do nothing and return successfully */ |
808 | if ( clazz == &ft_bitmap_glyph_class ) |
809 | goto Exit; |
810 | |
811 | if ( !clazz->glyph_prepare ) |
812 | goto Bad; |
813 | |
814 | /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ |
815 | /* then calling FT_Render_Glyph_Internal() */ |
816 | |
817 | FT_ZERO( &dummy ); |
818 | FT_ZERO( &dummy_internal ); |
819 | dummy.internal = &dummy_internal; |
820 | dummy.library = library; |
821 | dummy.format = clazz->glyph_format; |
822 | |
823 | /* create result bitmap glyph */ |
824 | error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b ); |
825 | if ( error ) |
826 | goto Exit; |
827 | bitmap = (FT_BitmapGlyph)b; |
828 | |
829 | #if 1 |
830 | /* if `origin' is set, translate the glyph image */ |
831 | if ( origin ) |
832 | FT_Glyph_Transform( glyph, NULL, origin ); |
833 | #else |
834 | FT_UNUSED( origin ); |
835 | #endif |
836 | |
837 | /* prepare dummy slot for rendering */ |
838 | error = clazz->glyph_prepare( glyph, &dummy ); |
839 | if ( !error ) |
840 | error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); |
841 | |
842 | #ifdef FT_CONFIG_OPTION_SVG |
843 | if ( clazz == &ft_svg_glyph_class ) |
844 | { |
845 | FT_Memory memory = library->memory; |
846 | |
847 | |
848 | FT_FREE( dummy.other ); |
849 | } |
850 | #endif |
851 | |
852 | #if 1 |
853 | if ( !destroy && origin ) |
854 | { |
855 | FT_Vector v; |
856 | |
857 | |
858 | v.x = -origin->x; |
859 | v.y = -origin->y; |
860 | FT_Glyph_Transform( glyph, NULL, &v ); |
861 | } |
862 | #endif |
863 | |
864 | if ( error ) |
865 | goto Exit; |
866 | |
867 | /* in case of success, copy the bitmap to the glyph bitmap */ |
868 | error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); |
869 | if ( error ) |
870 | goto Exit; |
871 | |
872 | /* copy advance */ |
873 | bitmap->root.advance = glyph->advance; |
874 | |
875 | if ( destroy ) |
876 | FT_Done_Glyph( glyph ); |
877 | |
878 | *the_glyph = FT_GLYPH( bitmap ); |
879 | |
880 | Exit: |
881 | if ( error && bitmap ) |
882 | FT_Done_Glyph( FT_GLYPH( bitmap ) ); |
883 | |
884 | return error; |
885 | |
886 | Bad: |
887 | error = FT_THROW( Invalid_Argument ); |
888 | goto Exit; |
889 | } |
890 | |
891 | |
892 | /* documentation is in ftglyph.h */ |
893 | |
894 | FT_EXPORT_DEF( void ) |
895 | FT_Done_Glyph( FT_Glyph glyph ) |
896 | { |
897 | if ( glyph ) |
898 | { |
899 | FT_Memory memory = glyph->library->memory; |
900 | const FT_Glyph_Class* clazz = glyph->clazz; |
901 | |
902 | |
903 | if ( clazz->glyph_done ) |
904 | clazz->glyph_done( glyph ); |
905 | |
906 | FT_FREE( glyph ); |
907 | } |
908 | } |
909 | |
910 | |
911 | /* END */ |
912 | |