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