1 | /**************************************************************************** |
2 | * |
3 | * ftglyph.c |
4 | * |
5 | * FreeType convenience functions to handle glyphs (body). |
6 | * |
7 | * Copyright (C) 1996-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 | * |
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 <ft2build.h> |
32 | #include FT_INTERNAL_DEBUG_H |
33 | |
34 | #include FT_GLYPH_H |
35 | #include FT_OUTLINE_H |
36 | #include FT_BITMAP_H |
37 | #include FT_INTERNAL_OBJECTS_H |
38 | |
39 | |
40 | /************************************************************************** |
41 | * |
42 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
43 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
44 | * messages during execution. |
45 | */ |
46 | #undef FT_COMPONENT |
47 | #define FT_COMPONENT glyph |
48 | |
49 | |
50 | /*************************************************************************/ |
51 | /*************************************************************************/ |
52 | /**** ****/ |
53 | /**** FT_BitmapGlyph support ****/ |
54 | /**** ****/ |
55 | /*************************************************************************/ |
56 | /*************************************************************************/ |
57 | |
58 | FT_CALLBACK_DEF( FT_Error ) |
59 | ft_bitmap_glyph_init( FT_Glyph bitmap_glyph, |
60 | FT_GlyphSlot slot ) |
61 | { |
62 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
63 | FT_Error error = FT_Err_Ok; |
64 | FT_Library library = FT_GLYPH( glyph )->library; |
65 | |
66 | |
67 | if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) |
68 | { |
69 | error = FT_THROW( Invalid_Glyph_Format ); |
70 | goto Exit; |
71 | } |
72 | |
73 | glyph->left = slot->bitmap_left; |
74 | glyph->top = slot->bitmap_top; |
75 | |
76 | /* do lazy copying whenever possible */ |
77 | if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) |
78 | { |
79 | glyph->bitmap = slot->bitmap; |
80 | slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; |
81 | } |
82 | else |
83 | { |
84 | FT_Bitmap_Init( &glyph->bitmap ); |
85 | error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); |
86 | } |
87 | |
88 | Exit: |
89 | return error; |
90 | } |
91 | |
92 | |
93 | FT_CALLBACK_DEF( FT_Error ) |
94 | ft_bitmap_glyph_copy( FT_Glyph bitmap_source, |
95 | FT_Glyph bitmap_target ) |
96 | { |
97 | FT_Library library = bitmap_source->library; |
98 | FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source; |
99 | FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target; |
100 | |
101 | |
102 | target->left = source->left; |
103 | target->top = source->top; |
104 | |
105 | return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); |
106 | } |
107 | |
108 | |
109 | FT_CALLBACK_DEF( void ) |
110 | ft_bitmap_glyph_done( FT_Glyph bitmap_glyph ) |
111 | { |
112 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
113 | FT_Library library = FT_GLYPH( glyph )->library; |
114 | |
115 | |
116 | FT_Bitmap_Done( library, &glyph->bitmap ); |
117 | } |
118 | |
119 | |
120 | FT_CALLBACK_DEF( void ) |
121 | ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph, |
122 | FT_BBox* cbox ) |
123 | { |
124 | FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; |
125 | |
126 | |
127 | cbox->xMin = glyph->left * 64; |
128 | cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 ); |
129 | cbox->yMax = glyph->top * 64; |
130 | cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 ); |
131 | } |
132 | |
133 | |
134 | FT_DEFINE_GLYPH( |
135 | ft_bitmap_glyph_class, |
136 | |
137 | sizeof ( FT_BitmapGlyphRec ), |
138 | FT_GLYPH_FORMAT_BITMAP, |
139 | |
140 | ft_bitmap_glyph_init, /* FT_Glyph_InitFunc glyph_init */ |
141 | ft_bitmap_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ |
142 | ft_bitmap_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ |
143 | NULL, /* FT_Glyph_TransformFunc glyph_transform */ |
144 | ft_bitmap_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ |
145 | NULL /* FT_Glyph_PrepareFunc glyph_prepare */ |
146 | ) |
147 | |
148 | |
149 | /*************************************************************************/ |
150 | /*************************************************************************/ |
151 | /**** ****/ |
152 | /**** FT_OutlineGlyph support ****/ |
153 | /**** ****/ |
154 | /*************************************************************************/ |
155 | /*************************************************************************/ |
156 | |
157 | |
158 | FT_CALLBACK_DEF( FT_Error ) |
159 | ft_outline_glyph_init( FT_Glyph outline_glyph, |
160 | FT_GlyphSlot slot ) |
161 | { |
162 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
163 | FT_Error error = FT_Err_Ok; |
164 | FT_Library library = FT_GLYPH( glyph )->library; |
165 | FT_Outline* source = &slot->outline; |
166 | FT_Outline* target = &glyph->outline; |
167 | |
168 | |
169 | /* check format in glyph slot */ |
170 | if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) |
171 | { |
172 | error = FT_THROW( Invalid_Glyph_Format ); |
173 | goto Exit; |
174 | } |
175 | |
176 | /* allocate new outline */ |
177 | error = FT_Outline_New( library, |
178 | (FT_UInt)source->n_points, |
179 | source->n_contours, |
180 | &glyph->outline ); |
181 | if ( error ) |
182 | goto Exit; |
183 | |
184 | FT_Outline_Copy( source, target ); |
185 | |
186 | Exit: |
187 | return error; |
188 | } |
189 | |
190 | |
191 | FT_CALLBACK_DEF( void ) |
192 | ft_outline_glyph_done( FT_Glyph outline_glyph ) |
193 | { |
194 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
195 | |
196 | |
197 | FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); |
198 | } |
199 | |
200 | |
201 | FT_CALLBACK_DEF( FT_Error ) |
202 | ft_outline_glyph_copy( FT_Glyph outline_source, |
203 | FT_Glyph outline_target ) |
204 | { |
205 | FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source; |
206 | FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target; |
207 | FT_Error error; |
208 | FT_Library library = FT_GLYPH( source )->library; |
209 | |
210 | |
211 | error = FT_Outline_New( library, |
212 | (FT_UInt)source->outline.n_points, |
213 | source->outline.n_contours, |
214 | &target->outline ); |
215 | if ( !error ) |
216 | FT_Outline_Copy( &source->outline, &target->outline ); |
217 | |
218 | return error; |
219 | } |
220 | |
221 | |
222 | FT_CALLBACK_DEF( void ) |
223 | ft_outline_glyph_transform( FT_Glyph outline_glyph, |
224 | const FT_Matrix* matrix, |
225 | const FT_Vector* delta ) |
226 | { |
227 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
228 | |
229 | |
230 | if ( matrix ) |
231 | FT_Outline_Transform( &glyph->outline, matrix ); |
232 | |
233 | if ( delta ) |
234 | FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); |
235 | } |
236 | |
237 | |
238 | FT_CALLBACK_DEF( void ) |
239 | ft_outline_glyph_bbox( FT_Glyph outline_glyph, |
240 | FT_BBox* bbox ) |
241 | { |
242 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
243 | |
244 | |
245 | FT_Outline_Get_CBox( &glyph->outline, bbox ); |
246 | } |
247 | |
248 | |
249 | FT_CALLBACK_DEF( FT_Error ) |
250 | ft_outline_glyph_prepare( FT_Glyph outline_glyph, |
251 | FT_GlyphSlot slot ) |
252 | { |
253 | FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; |
254 | |
255 | |
256 | slot->format = FT_GLYPH_FORMAT_OUTLINE; |
257 | slot->outline = glyph->outline; |
258 | slot->outline.flags &= ~FT_OUTLINE_OWNER; |
259 | |
260 | return FT_Err_Ok; |
261 | } |
262 | |
263 | |
264 | FT_DEFINE_GLYPH( |
265 | ft_outline_glyph_class, |
266 | |
267 | sizeof ( FT_OutlineGlyphRec ), |
268 | FT_GLYPH_FORMAT_OUTLINE, |
269 | |
270 | ft_outline_glyph_init, /* FT_Glyph_InitFunc glyph_init */ |
271 | ft_outline_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ |
272 | ft_outline_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ |
273 | ft_outline_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ |
274 | ft_outline_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ |
275 | ft_outline_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ |
276 | ) |
277 | |
278 | |
279 | /*************************************************************************/ |
280 | /*************************************************************************/ |
281 | /**** ****/ |
282 | /**** FT_Glyph class and API ****/ |
283 | /**** ****/ |
284 | /*************************************************************************/ |
285 | /*************************************************************************/ |
286 | |
287 | static FT_Error |
288 | ft_new_glyph( FT_Library library, |
289 | const FT_Glyph_Class* clazz, |
290 | FT_Glyph* aglyph ) |
291 | { |
292 | FT_Memory memory = library->memory; |
293 | FT_Error error; |
294 | FT_Glyph glyph = NULL; |
295 | |
296 | |
297 | *aglyph = NULL; |
298 | |
299 | if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) |
300 | { |
301 | glyph->library = library; |
302 | glyph->clazz = clazz; |
303 | glyph->format = clazz->glyph_format; |
304 | |
305 | *aglyph = glyph; |
306 | } |
307 | |
308 | return error; |
309 | } |
310 | |
311 | |
312 | /* documentation is in ftglyph.h */ |
313 | |
314 | FT_EXPORT_DEF( FT_Error ) |
315 | FT_Glyph_Copy( FT_Glyph source, |
316 | FT_Glyph *target ) |
317 | { |
318 | FT_Glyph copy; |
319 | FT_Error error; |
320 | const FT_Glyph_Class* clazz; |
321 | |
322 | |
323 | /* check arguments */ |
324 | if ( !target || !source || !source->clazz ) |
325 | { |
326 | error = FT_THROW( Invalid_Argument ); |
327 | goto Exit; |
328 | } |
329 | |
330 | *target = NULL; |
331 | |
332 | if ( !source || !source->clazz ) |
333 | { |
334 | error = FT_THROW( Invalid_Argument ); |
335 | goto Exit; |
336 | } |
337 | |
338 | clazz = source->clazz; |
339 | error = ft_new_glyph( source->library, clazz, © ); |
340 | if ( error ) |
341 | goto Exit; |
342 | |
343 | copy->advance = source->advance; |
344 | copy->format = source->format; |
345 | |
346 | if ( clazz->glyph_copy ) |
347 | error = clazz->glyph_copy( source, copy ); |
348 | |
349 | if ( error ) |
350 | FT_Done_Glyph( copy ); |
351 | else |
352 | *target = copy; |
353 | |
354 | Exit: |
355 | return error; |
356 | } |
357 | |
358 | |
359 | /* documentation is in ftglyph.h */ |
360 | |
361 | FT_EXPORT( FT_Error ) |
362 | FT_New_Glyph( FT_Library library, |
363 | FT_Glyph_Format format, |
364 | FT_Glyph *aglyph ) |
365 | { |
366 | const FT_Glyph_Class* clazz = NULL; |
367 | |
368 | if ( !library || !aglyph ) |
369 | return FT_THROW( Invalid_Argument ); |
370 | |
371 | /* if it is a bitmap, that's easy :-) */ |
372 | if ( format == FT_GLYPH_FORMAT_BITMAP ) |
373 | clazz = &ft_bitmap_glyph_class; |
374 | |
375 | /* if it is an outline */ |
376 | else if ( format == FT_GLYPH_FORMAT_OUTLINE ) |
377 | clazz = &ft_outline_glyph_class; |
378 | |
379 | else |
380 | { |
381 | /* try to find a renderer that supports the glyph image format */ |
382 | FT_Renderer render = FT_Lookup_Renderer( library, format, 0 ); |
383 | |
384 | |
385 | if ( render ) |
386 | clazz = &render->glyph_class; |
387 | } |
388 | |
389 | if ( !clazz ) |
390 | return FT_THROW( Invalid_Glyph_Format ); |
391 | |
392 | /* create FT_Glyph object */ |
393 | return ft_new_glyph( library, clazz, aglyph ); |
394 | } |
395 | |
396 | |
397 | /* documentation is in ftglyph.h */ |
398 | |
399 | FT_EXPORT_DEF( FT_Error ) |
400 | FT_Get_Glyph( FT_GlyphSlot slot, |
401 | FT_Glyph *aglyph ) |
402 | { |
403 | FT_Error error; |
404 | FT_Glyph glyph; |
405 | |
406 | |
407 | if ( !slot ) |
408 | return FT_THROW( Invalid_Slot_Handle ); |
409 | |
410 | if ( !aglyph ) |
411 | return FT_THROW( Invalid_Argument ); |
412 | |
413 | /* create FT_Glyph object */ |
414 | error = FT_New_Glyph( slot->library, slot->format, &glyph ); |
415 | if ( error ) |
416 | goto Exit; |
417 | |
418 | /* copy advance while converting 26.6 to 16.16 format */ |
419 | if ( slot->advance.x >= 0x8000L * 64 || |
420 | slot->advance.x <= -0x8000L * 64 ) |
421 | { |
422 | FT_ERROR(( "FT_Get_Glyph: advance width too large\n" )); |
423 | error = FT_THROW( Invalid_Argument ); |
424 | goto Exit2; |
425 | } |
426 | if ( slot->advance.y >= 0x8000L * 64 || |
427 | slot->advance.y <= -0x8000L * 64 ) |
428 | { |
429 | FT_ERROR(( "FT_Get_Glyph: advance height too large\n" )); |
430 | error = FT_THROW( Invalid_Argument ); |
431 | goto Exit2; |
432 | } |
433 | |
434 | glyph->advance.x = slot->advance.x * 1024; |
435 | glyph->advance.y = slot->advance.y * 1024; |
436 | |
437 | /* now import the image from the glyph slot */ |
438 | error = glyph->clazz->glyph_init( glyph, slot ); |
439 | |
440 | Exit2: |
441 | /* if an error occurred, destroy the glyph */ |
442 | if ( error ) |
443 | FT_Done_Glyph( glyph ); |
444 | else |
445 | *aglyph = glyph; |
446 | |
447 | Exit: |
448 | return error; |
449 | } |
450 | |
451 | |
452 | /* documentation is in ftglyph.h */ |
453 | |
454 | FT_EXPORT_DEF( FT_Error ) |
455 | FT_Glyph_Transform( FT_Glyph glyph, |
456 | FT_Matrix* matrix, |
457 | FT_Vector* delta ) |
458 | { |
459 | FT_Error error = FT_Err_Ok; |
460 | |
461 | |
462 | if ( !glyph || !glyph->clazz ) |
463 | error = FT_THROW( Invalid_Argument ); |
464 | else |
465 | { |
466 | const FT_Glyph_Class* clazz = glyph->clazz; |
467 | |
468 | |
469 | if ( clazz->glyph_transform ) |
470 | { |
471 | /* transform glyph image */ |
472 | clazz->glyph_transform( glyph, matrix, delta ); |
473 | |
474 | /* transform advance vector */ |
475 | if ( matrix ) |
476 | FT_Vector_Transform( &glyph->advance, matrix ); |
477 | } |
478 | else |
479 | error = FT_THROW( Invalid_Glyph_Format ); |
480 | } |
481 | return error; |
482 | } |
483 | |
484 | |
485 | /* documentation is in ftglyph.h */ |
486 | |
487 | FT_EXPORT_DEF( void ) |
488 | FT_Glyph_Get_CBox( FT_Glyph glyph, |
489 | FT_UInt bbox_mode, |
490 | FT_BBox *acbox ) |
491 | { |
492 | const FT_Glyph_Class* clazz; |
493 | |
494 | |
495 | if ( !acbox ) |
496 | return; |
497 | |
498 | acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; |
499 | |
500 | if ( !glyph || !glyph->clazz ) |
501 | return; |
502 | |
503 | clazz = glyph->clazz; |
504 | if ( !clazz->glyph_bbox ) |
505 | return; |
506 | |
507 | /* retrieve bbox in 26.6 coordinates */ |
508 | clazz->glyph_bbox( glyph, acbox ); |
509 | |
510 | /* perform grid fitting if needed */ |
511 | if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || |
512 | bbox_mode == FT_GLYPH_BBOX_PIXELS ) |
513 | { |
514 | acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); |
515 | acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); |
516 | acbox->xMax = FT_PIX_CEIL_LONG( acbox->xMax ); |
517 | acbox->yMax = FT_PIX_CEIL_LONG( acbox->yMax ); |
518 | } |
519 | |
520 | /* convert to integer pixels if needed */ |
521 | if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || |
522 | bbox_mode == FT_GLYPH_BBOX_PIXELS ) |
523 | { |
524 | acbox->xMin >>= 6; |
525 | acbox->yMin >>= 6; |
526 | acbox->xMax >>= 6; |
527 | acbox->yMax >>= 6; |
528 | } |
529 | } |
530 | |
531 | |
532 | /* documentation is in ftglyph.h */ |
533 | |
534 | FT_EXPORT_DEF( FT_Error ) |
535 | FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, |
536 | FT_Render_Mode render_mode, |
537 | FT_Vector* origin, |
538 | FT_Bool destroy ) |
539 | { |
540 | FT_GlyphSlotRec dummy; |
541 | FT_GlyphSlot_InternalRec dummy_internal; |
542 | FT_Error error = FT_Err_Ok; |
543 | FT_Glyph b, glyph; |
544 | FT_BitmapGlyph bitmap = NULL; |
545 | const FT_Glyph_Class* clazz; |
546 | |
547 | FT_Library library; |
548 | |
549 | |
550 | /* check argument */ |
551 | if ( !the_glyph ) |
552 | goto Bad; |
553 | glyph = *the_glyph; |
554 | if ( !glyph ) |
555 | goto Bad; |
556 | |
557 | clazz = glyph->clazz; |
558 | library = glyph->library; |
559 | if ( !library || !clazz ) |
560 | goto Bad; |
561 | |
562 | /* when called with a bitmap glyph, do nothing and return successfully */ |
563 | if ( clazz == &ft_bitmap_glyph_class ) |
564 | goto Exit; |
565 | |
566 | if ( !clazz->glyph_prepare ) |
567 | goto Bad; |
568 | |
569 | /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ |
570 | /* then calling FT_Render_Glyph_Internal() */ |
571 | |
572 | FT_ZERO( &dummy ); |
573 | FT_ZERO( &dummy_internal ); |
574 | dummy.internal = &dummy_internal; |
575 | dummy.library = library; |
576 | dummy.format = clazz->glyph_format; |
577 | |
578 | /* create result bitmap glyph */ |
579 | error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b ); |
580 | if ( error ) |
581 | goto Exit; |
582 | bitmap = (FT_BitmapGlyph)b; |
583 | |
584 | #if 1 |
585 | /* if `origin' is set, translate the glyph image */ |
586 | if ( origin ) |
587 | FT_Glyph_Transform( glyph, 0, origin ); |
588 | #else |
589 | FT_UNUSED( origin ); |
590 | #endif |
591 | |
592 | /* prepare dummy slot for rendering */ |
593 | error = clazz->glyph_prepare( glyph, &dummy ); |
594 | if ( !error ) |
595 | error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); |
596 | |
597 | #if 1 |
598 | if ( !destroy && origin ) |
599 | { |
600 | FT_Vector v; |
601 | |
602 | |
603 | v.x = -origin->x; |
604 | v.y = -origin->y; |
605 | FT_Glyph_Transform( glyph, 0, &v ); |
606 | } |
607 | #endif |
608 | |
609 | if ( error ) |
610 | goto Exit; |
611 | |
612 | /* in case of success, copy the bitmap to the glyph bitmap */ |
613 | error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); |
614 | if ( error ) |
615 | goto Exit; |
616 | |
617 | /* copy advance */ |
618 | bitmap->root.advance = glyph->advance; |
619 | |
620 | if ( destroy ) |
621 | FT_Done_Glyph( glyph ); |
622 | |
623 | *the_glyph = FT_GLYPH( bitmap ); |
624 | |
625 | Exit: |
626 | if ( error && bitmap ) |
627 | FT_Done_Glyph( FT_GLYPH( bitmap ) ); |
628 | |
629 | return error; |
630 | |
631 | Bad: |
632 | error = FT_THROW( Invalid_Argument ); |
633 | goto Exit; |
634 | } |
635 | |
636 | |
637 | /* documentation is in ftglyph.h */ |
638 | |
639 | FT_EXPORT_DEF( void ) |
640 | FT_Done_Glyph( FT_Glyph glyph ) |
641 | { |
642 | if ( glyph ) |
643 | { |
644 | FT_Memory memory = glyph->library->memory; |
645 | const FT_Glyph_Class* clazz = glyph->clazz; |
646 | |
647 | |
648 | if ( clazz->glyph_done ) |
649 | clazz->glyph_done( glyph ); |
650 | |
651 | FT_FREE( glyph ); |
652 | } |
653 | } |
654 | |
655 | |
656 | /* END */ |
657 | |