]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************/ | |
2 | /* */ | |
3 | /* ftglyph.c */ | |
4 | /* */ | |
5 | /* FreeType convenience functions to handle glyphs (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 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/ftglyph.h> | |
32 | #include <freetype/ftoutln.h> | |
33 | #include <freetype/internal/ftobjs.h> | |
34 | ||
35 | ||
36 | /*************************************************************************/ | |
37 | /* */ | |
38 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
39 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
40 | /* messages during execution. */ | |
41 | /* */ | |
42 | #undef FT_COMPONENT | |
43 | #define FT_COMPONENT trace_glyph | |
44 | ||
45 | ||
46 | /*************************************************************************/ | |
47 | /*************************************************************************/ | |
48 | /**** ****/ | |
49 | /**** Convenience functions ****/ | |
50 | /**** ****/ | |
51 | /*************************************************************************/ | |
52 | /*************************************************************************/ | |
53 | ||
54 | ||
55 | /*************************************************************************/ | |
56 | /* */ | |
57 | /* <Function> */ | |
58 | /* FT_Matrix_Multiply */ | |
59 | /* */ | |
60 | /* <Description> */ | |
61 | /* Performs the matrix operation `b = a*b'. */ | |
62 | /* */ | |
63 | /* <Input> */ | |
64 | /* a :: A pointer to matrix `a'. */ | |
65 | /* */ | |
66 | /* <InOut> */ | |
67 | /* b :: A pointer to matrix `b'. */ | |
68 | /* */ | |
69 | /* <MT-Note> */ | |
70 | /* Yes. */ | |
71 | /* */ | |
72 | /* <Note> */ | |
73 | /* The result is undefined if either `a' or `b' is zero. */ | |
74 | /* */ | |
75 | FT_EXPORT_FUNC( void ) FT_Matrix_Multiply( FT_Matrix* a, | |
76 | FT_Matrix* b ) | |
77 | { | |
78 | FT_Fixed xx, xy, yx, yy; | |
79 | ||
80 | ||
81 | if ( !a || !b ) | |
82 | return; | |
83 | ||
84 | xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx ); | |
85 | xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy ); | |
86 | yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx ); | |
87 | yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy ); | |
88 | ||
89 | b->xx = xx; b->xy = xy; | |
90 | b->yx = yx; b->yy = yy; | |
91 | } | |
92 | ||
93 | ||
94 | /*************************************************************************/ | |
95 | /* */ | |
96 | /* <Function> */ | |
97 | /* FT_Matrix_Invert */ | |
98 | /* */ | |
99 | /* <Description> */ | |
100 | /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */ | |
101 | /* */ | |
102 | /* <InOut> */ | |
103 | /* matrix :: A pointer to the target matrix. Remains untouched in */ | |
104 | /* case of error. */ | |
105 | /* */ | |
106 | /* <Return> */ | |
107 | /* FreeType error code. 0 means success. */ | |
108 | /* */ | |
109 | /* <MT-Note> */ | |
110 | /* Yes. */ | |
111 | /* */ | |
112 | FT_EXPORT_FUNC( FT_Error ) FT_Matrix_Invert( FT_Matrix* matrix ) | |
113 | { | |
114 | FT_Pos delta, xx, yy; | |
115 | ||
116 | ||
117 | if ( !matrix ) | |
118 | return FT_Err_Invalid_Argument; | |
119 | ||
120 | /* compute discriminant */ | |
121 | delta = FT_MulFix( matrix->xx, matrix->yy ) - | |
122 | FT_MulFix( matrix->xy, matrix->yx ); | |
123 | ||
124 | if ( !delta ) | |
125 | return FT_Err_Invalid_Argument; /* matrix can't be inverted */ | |
126 | ||
127 | matrix->xy = - FT_DivFix( matrix->xy, delta ); | |
128 | matrix->yx = - FT_DivFix( matrix->yx, delta ); | |
129 | ||
130 | xx = matrix->xx; | |
131 | yy = matrix->yy; | |
132 | ||
133 | matrix->xx = FT_DivFix( yy, delta ); | |
134 | matrix->yy = FT_DivFix( xx, delta ); | |
135 | ||
136 | return FT_Err_Ok; | |
137 | } | |
138 | ||
139 | ||
140 | /*************************************************************************/ | |
141 | /*************************************************************************/ | |
142 | /**** ****/ | |
143 | /**** FT_BitmapGlyph support ****/ | |
144 | /**** ****/ | |
145 | /*************************************************************************/ | |
146 | /*************************************************************************/ | |
147 | ||
148 | static | |
149 | FT_Error ft_bitmap_copy( FT_Memory memory, | |
150 | FT_Bitmap* source, | |
151 | FT_Bitmap* target ) | |
152 | { | |
153 | FT_Error error; | |
154 | FT_Int pitch = source->pitch; | |
155 | FT_ULong size; | |
156 | ||
157 | ||
158 | *target = *source; | |
159 | ||
160 | if ( pitch < 0 ) | |
161 | pitch = -pitch; | |
162 | ||
163 | size = (FT_ULong)( pitch * source->rows ); | |
164 | ||
165 | if ( !ALLOC( target->buffer, size ) ) | |
166 | MEM_Copy( source->buffer, target->buffer, size ); | |
167 | ||
168 | return error; | |
169 | } | |
170 | ||
171 | ||
172 | static | |
173 | FT_Error ft_bitmap_glyph_init( FT_BitmapGlyph glyph, | |
174 | FT_GlyphSlot slot ) | |
175 | { | |
176 | FT_Error error = FT_Err_Ok; | |
177 | FT_Library library = FT_GLYPH(glyph)->library; | |
178 | FT_Memory memory = library->memory; | |
179 | ||
180 | ||
181 | if ( slot->format != ft_glyph_format_bitmap ) | |
182 | { | |
183 | error = FT_Err_Invalid_Glyph_Format; | |
184 | goto Exit; | |
185 | } | |
186 | ||
187 | /* grab the bitmap in the slot - do lazy copying whenever possible */ | |
188 | glyph->bitmap = slot->bitmap; | |
189 | glyph->left = slot->bitmap_left; | |
190 | glyph->top = slot->bitmap_top; | |
191 | ||
192 | if ( slot->flags & ft_glyph_own_bitmap ) | |
193 | slot->flags &= ~ft_glyph_own_bitmap; | |
194 | else | |
195 | { | |
196 | /* copy the bitmap into a new buffer */ | |
197 | error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap ); | |
198 | } | |
199 | ||
200 | Exit: | |
201 | return error; | |
202 | } | |
203 | ||
204 | ||
205 | static | |
206 | FT_Error ft_bitmap_glyph_copy( FT_BitmapGlyph source, | |
207 | FT_BitmapGlyph target ) | |
208 | { | |
209 | FT_Memory memory = source->root.library->memory; | |
210 | ||
211 | ||
212 | target->left = source->left; | |
213 | target->top = source->top; | |
214 | ||
215 | return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap ); | |
216 | } | |
217 | ||
218 | ||
219 | static | |
220 | void ft_bitmap_glyph_done( FT_BitmapGlyph glyph ) | |
221 | { | |
222 | FT_Memory memory = FT_GLYPH(glyph)->library->memory; | |
223 | ||
224 | ||
225 | FREE( glyph->bitmap.buffer ); | |
226 | } | |
227 | ||
228 | ||
229 | static | |
230 | void ft_bitmap_glyph_bbox( FT_BitmapGlyph glyph, | |
231 | FT_BBox* cbox ) | |
232 | { | |
233 | cbox->xMin = glyph->left << 6; | |
234 | cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 ); | |
235 | cbox->yMax = glyph->top << 6; | |
236 | cbox->yMin = cbox->xMax - ( glyph->bitmap.rows << 6 ); | |
237 | } | |
238 | ||
239 | ||
240 | const FT_Glyph_Class ft_bitmap_glyph_class = | |
241 | { | |
242 | sizeof( FT_BitmapGlyphRec ), | |
243 | ft_glyph_format_bitmap, | |
244 | ||
245 | (FT_Glyph_Init_Func) ft_bitmap_glyph_init, | |
246 | (FT_Glyph_Done_Func) ft_bitmap_glyph_done, | |
247 | (FT_Glyph_Copy_Func) ft_bitmap_glyph_copy, | |
248 | (FT_Glyph_Transform_Func)0, | |
249 | (FT_Glyph_BBox_Func) ft_bitmap_glyph_bbox, | |
250 | (FT_Glyph_Prepare_Func) 0 | |
251 | }; | |
252 | ||
253 | ||
254 | /*************************************************************************/ | |
255 | /*************************************************************************/ | |
256 | /**** ****/ | |
257 | /**** FT_OutlineGlyph support ****/ | |
258 | /**** ****/ | |
259 | /*************************************************************************/ | |
260 | /*************************************************************************/ | |
261 | ||
262 | ||
263 | static | |
264 | FT_Error ft_outline_glyph_init( FT_OutlineGlyph glyph, | |
265 | FT_GlyphSlot slot ) | |
266 | { | |
267 | FT_Error error = FT_Err_Ok; | |
268 | FT_Library library = FT_GLYPH(glyph)->library; | |
269 | FT_Outline* source = &slot->outline; | |
270 | FT_Outline* target = &glyph->outline; | |
271 | ||
272 | ||
273 | /* check format in glyph slot */ | |
274 | if ( slot->format != ft_glyph_format_outline ) | |
275 | { | |
276 | error = FT_Err_Invalid_Glyph_Format; | |
277 | goto Exit; | |
278 | } | |
279 | ||
280 | /* allocate new outline */ | |
281 | error = FT_Outline_New( library, source->n_points, source->n_contours, | |
282 | &glyph->outline ); | |
283 | if ( error ) | |
284 | goto Exit; | |
285 | ||
286 | /* copy it */ | |
287 | MEM_Copy( target->points, source->points, | |
288 | source->n_points * sizeof ( FT_Vector ) ); | |
289 | ||
290 | MEM_Copy( target->tags, source->tags, | |
291 | source->n_points * sizeof ( FT_Byte ) ); | |
292 | ||
293 | MEM_Copy( target->contours, source->contours, | |
294 | source->n_contours * sizeof ( FT_Short ) ); | |
295 | ||
296 | /* copy all flags, except the `ft_outline_owner' one */ | |
297 | target->flags = source->flags | ft_outline_owner; | |
298 | ||
299 | Exit: | |
300 | return error; | |
301 | } | |
302 | ||
303 | ||
304 | static | |
305 | void ft_outline_glyph_done( FT_OutlineGlyph glyph ) | |
306 | { | |
307 | FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); | |
308 | } | |
309 | ||
310 | ||
311 | static | |
312 | FT_Error ft_outline_glyph_copy( FT_OutlineGlyph source, | |
313 | FT_OutlineGlyph target ) | |
314 | { | |
315 | FT_Error error; | |
316 | FT_Library library = FT_GLYPH( source )->library; | |
317 | ||
318 | ||
319 | error = FT_Outline_New( library, source->outline.n_points, | |
320 | source->outline.n_contours, &target->outline ); | |
321 | if ( !error ) | |
322 | FT_Outline_Copy( &source->outline, &target->outline ); | |
323 | ||
324 | return error; | |
325 | } | |
326 | ||
327 | ||
328 | static | |
329 | void ft_outline_glyph_transform( FT_OutlineGlyph glyph, | |
330 | FT_Matrix* matrix, | |
331 | FT_Vector* delta ) | |
332 | { | |
333 | if ( matrix ) | |
334 | FT_Outline_Transform( &glyph->outline, matrix ); | |
335 | ||
336 | if ( delta ) | |
337 | FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); | |
338 | } | |
339 | ||
340 | ||
341 | static | |
342 | void ft_outline_glyph_bbox( FT_OutlineGlyph glyph, | |
343 | FT_BBox* bbox ) | |
344 | { | |
345 | FT_Outline_Get_CBox( &glyph->outline, bbox ); | |
346 | } | |
347 | ||
348 | ||
349 | static | |
350 | FT_Error ft_outline_glyph_prepare( FT_OutlineGlyph glyph, | |
351 | FT_GlyphSlot slot ) | |
352 | { | |
353 | slot->format = ft_glyph_format_outline; | |
354 | slot->outline = glyph->outline; | |
355 | slot->outline.flags &= ~ft_outline_owner; | |
356 | ||
357 | return FT_Err_Ok; | |
358 | } | |
359 | ||
360 | ||
361 | const FT_Glyph_Class ft_outline_glyph_class = | |
362 | { | |
363 | sizeof( FT_OutlineGlyphRec ), | |
364 | ft_glyph_format_outline, | |
365 | ||
366 | (FT_Glyph_Init_Func) ft_outline_glyph_init, | |
367 | (FT_Glyph_Done_Func) ft_outline_glyph_done, | |
368 | (FT_Glyph_Copy_Func) ft_outline_glyph_copy, | |
369 | (FT_Glyph_Transform_Func)ft_outline_glyph_transform, | |
370 | (FT_Glyph_BBox_Func) ft_outline_glyph_bbox, | |
371 | (FT_Glyph_Prepare_Func) ft_outline_glyph_prepare | |
372 | }; | |
373 | ||
374 | ||
375 | /*************************************************************************/ | |
376 | /*************************************************************************/ | |
377 | /**** ****/ | |
378 | /**** FT_Glyph class and API ****/ | |
379 | /**** ****/ | |
380 | /*************************************************************************/ | |
381 | /*************************************************************************/ | |
382 | ||
383 | static | |
384 | FT_Error ft_new_glyph( FT_Library library, | |
385 | const FT_Glyph_Class* clazz, | |
386 | FT_Glyph* aglyph ) | |
387 | { | |
388 | FT_Memory memory = library->memory; | |
389 | FT_Error error; | |
390 | FT_Glyph glyph; | |
391 | ||
392 | ||
393 | *aglyph = 0; | |
394 | ||
395 | if ( !ALLOC( glyph, clazz->glyph_size ) ) | |
396 | { | |
397 | glyph->library = library; | |
398 | glyph->clazz = clazz; | |
399 | glyph->format = clazz->glyph_format; | |
400 | ||
401 | *aglyph = glyph; | |
402 | } | |
403 | ||
404 | return error; | |
405 | } | |
406 | ||
407 | ||
408 | /*************************************************************************/ | |
409 | /* */ | |
410 | /* <Function> */ | |
411 | /* FT_Glyph_Copy */ | |
412 | /* */ | |
413 | /* <Description> */ | |
414 | /* A function used to copy a glyph image. */ | |
415 | /* */ | |
416 | /* <Input> */ | |
417 | /* source :: A handle to the source glyph object. */ | |
418 | /* */ | |
419 | /* <Output> */ | |
420 | /* target :: A handle to the target glyph object. 0 in case of */ | |
421 | /* error. */ | |
422 | /* */ | |
423 | /* <Return> */ | |
424 | /* FreeType error code. 0 means success. */ | |
425 | /* */ | |
426 | FT_EXPORT_FUNC( FT_Error ) FT_Glyph_Copy( FT_Glyph source, | |
427 | FT_Glyph* target ) | |
428 | { | |
429 | FT_Glyph copy; | |
430 | FT_Error error; | |
431 | const FT_Glyph_Class* clazz; | |
432 | ||
433 | ||
434 | /* check arguments */ | |
435 | if ( !target || !source || !source->clazz ) | |
436 | { | |
437 | error = FT_Err_Invalid_Argument; | |
438 | goto Exit; | |
439 | } | |
440 | ||
441 | *target = 0; | |
442 | ||
443 | clazz = source->clazz; | |
444 | error = ft_new_glyph( source->library, clazz, © ); | |
445 | if ( error ) | |
446 | goto Exit; | |
447 | ||
448 | if ( clazz->glyph_copy ) | |
449 | error = clazz->glyph_copy( source, copy ); | |
450 | ||
451 | if ( error ) | |
452 | FT_Done_Glyph( copy ); | |
453 | else | |
454 | *target = copy; | |
455 | ||
456 | Exit: | |
457 | return error; | |
458 | } | |
459 | ||
460 | ||
461 | /*************************************************************************/ | |
462 | /* */ | |
463 | /* <Function> */ | |
464 | /* FT_Get_Glyph */ | |
465 | /* */ | |
466 | /* <Description> */ | |
467 | /* A function used to extract a glyph image from a slot. */ | |
468 | /* */ | |
469 | /* <Input> */ | |
470 | /* slot :: A handle to the source glyph slot. */ | |
471 | /* */ | |
472 | /* <Output> */ | |
473 | /* aglyph :: A handle to the glyph object. */ | |
474 | /* */ | |
475 | /* <Return> */ | |
476 | /* FreeType error code. 0 means success. */ | |
477 | /* */ | |
478 | FT_EXPORT_FUNC( FT_Error ) FT_Get_Glyph( FT_GlyphSlot slot, | |
479 | FT_Glyph* aglyph ) | |
480 | { | |
481 | FT_Library library = slot->library; | |
482 | FT_Error error; | |
483 | FT_Glyph glyph; | |
484 | ||
485 | const FT_Glyph_Class* clazz = 0; | |
486 | ||
487 | ||
488 | if ( !slot ) | |
489 | return FT_Err_Invalid_Slot_Handle; | |
490 | ||
491 | if ( !aglyph ) | |
492 | return FT_Err_Invalid_Argument; | |
493 | ||
494 | /* if it is a bitmap, that's easy :-) */ | |
495 | if ( slot->format == ft_glyph_format_bitmap ) | |
496 | clazz = &ft_bitmap_glyph_class; | |
497 | ||
498 | /* it it is an outline too */ | |
499 | else if ( slot->format == ft_glyph_format_outline ) | |
500 | clazz = &ft_outline_glyph_class; | |
501 | ||
502 | else | |
503 | { | |
504 | /* try to find a renderer that supports the glyph image format */ | |
505 | FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 ); | |
506 | ||
507 | ||
508 | if ( render ) | |
509 | clazz = &render->glyph_class; | |
510 | } | |
511 | ||
512 | if ( !clazz ) | |
513 | { | |
514 | error = FT_Err_Invalid_Glyph_Format; | |
515 | goto Exit; | |
516 | } | |
517 | ||
518 | /* create FT_Glyph object */ | |
519 | error = ft_new_glyph( library, clazz, &glyph ); | |
520 | if ( error ) | |
521 | goto Exit; | |
522 | ||
523 | /* copy advance while converting it to 16.16 format */ | |
524 | glyph->advance.x = slot->advance.x << 10; | |
525 | glyph->advance.y = slot->advance.y << 10; | |
526 | ||
527 | /* now import the image from the glyph slot */ | |
528 | error = clazz->glyph_init( glyph, slot ); | |
529 | ||
530 | /* if an error occurred, destroy the glyph */ | |
531 | if ( error ) | |
532 | FT_Done_Glyph( glyph ); | |
533 | else | |
534 | *aglyph = glyph; | |
535 | ||
536 | Exit: | |
537 | return error; | |
538 | } | |
539 | ||
540 | ||
541 | /*************************************************************************/ | |
542 | /* */ | |
543 | /* <Function> */ | |
544 | /* FT_Glyph_Transform */ | |
545 | /* */ | |
546 | /* <Description> */ | |
547 | /* Transforms a glyph image if its format is scalable. */ | |
548 | /* */ | |
549 | /* <Input> */ | |
550 | /* glyph :: A handle to the target glyph object. */ | |
551 | /* */ | |
552 | /* matrix :: A pointer to a 2x2 matrix to apply. */ | |
553 | /* */ | |
554 | /* delta :: A pointer to a 2d vector to apply. Coordinates are */ | |
555 | /* expressed in 1/64th of a pixel. */ | |
556 | /* */ | |
557 | /* <Return> */ | |
558 | /* FreeType error code (the glyph format is not scalable if it is */ | |
559 | /* not zero). */ | |
560 | /* */ | |
561 | /* <Note> */ | |
562 | /* The 2x2 transformation matrix is also applied to the glyph's */ | |
563 | /* advance vector. */ | |
564 | /* */ | |
565 | FT_EXPORT_FUNC( FT_Error ) FT_Glyph_Transform( FT_Glyph glyph, | |
566 | FT_Matrix* matrix, | |
567 | FT_Vector* delta ) | |
568 | { | |
569 | const FT_Glyph_Class* clazz; | |
570 | FT_Error error = FT_Err_Ok; | |
571 | ||
572 | ||
573 | if ( !glyph || !glyph->clazz ) | |
574 | error = FT_Err_Invalid_Argument; | |
575 | else | |
576 | { | |
577 | clazz = glyph->clazz; | |
578 | if ( clazz->glyph_transform ) | |
579 | { | |
580 | /* transform glyph image */ | |
581 | clazz->glyph_transform( glyph, matrix, delta ); | |
582 | ||
583 | /* transform advance vector */ | |
584 | if ( matrix ) | |
585 | FT_Vector_Transform( &glyph->advance, matrix ); | |
586 | } | |
587 | else | |
588 | error = FT_Err_Invalid_Glyph_Format; | |
589 | } | |
590 | return error; | |
591 | } | |
592 | ||
593 | ||
594 | /*************************************************************************/ | |
595 | /* */ | |
596 | /* <Function> */ | |
597 | /* FT_Glyph_Get_CBox */ | |
598 | /* */ | |
599 | /* <Description> */ | |
600 | /* Returns the glyph image's bounding box. */ | |
601 | /* */ | |
602 | /* <Input> */ | |
603 | /* glyph :: A handle to the source glyph object. */ | |
604 | /* */ | |
605 | /* mode :: A set of bit flags that indicate how to interpret the */ | |
606 | /* returned bounding box values. */ | |
607 | /* */ | |
608 | /* <Output> */ | |
609 | /* box :: The glyph bounding box. Coordinates are expressed in */ | |
610 | /* 1/64th of pixels if it is grid-fitted. */ | |
611 | /* */ | |
612 | /* <Note> */ | |
613 | /* Coordinates are relative to the glyph origin, using the Y-upwards */ | |
614 | /* convention. */ | |
615 | /* */ | |
616 | /* If `ft_glyph_bbox_subpixels' is set in `mode', the bbox */ | |
617 | /* coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels). */ | |
618 | /* Otherwise, coordinates are expressed in integer pixels. */ | |
619 | /* */ | |
620 | /* Note that the maximum coordinates are exclusive, which means that */ | |
621 | /* one can compute the width and height of the glyph image (be it in */ | |
622 | /* integer or 26.6 pixels) as: */ | |
623 | /* */ | |
624 | /* width = bbox.xMax - bbox.xMin; */ | |
625 | /* height = bbox.yMax - bbox.yMin; */ | |
626 | /* */ | |
627 | /* Note also that for 26.6 coordinates, if the */ | |
628 | /* `ft_glyph_bbox_gridfit' flag is set in `mode;, the coordinates */ | |
629 | /* will also be grid-fitted, which corresponds to: */ | |
630 | /* */ | |
631 | /* bbox.xMin = FLOOR(bbox.xMin); */ | |
632 | /* bbox.yMin = FLOOR(bbox.yMin); */ | |
633 | /* bbox.xMax = CEILING(bbox.xMax); */ | |
634 | /* bbox.yMax = CEILING(bbox.yMax); */ | |
635 | /* */ | |
636 | /* The default value (0) for `bbox_mode' is `ft_glyph_bbox_pixels'. */ | |
637 | /* */ | |
638 | FT_EXPORT_FUNC( void ) FT_Glyph_Get_CBox( FT_Glyph glyph, | |
639 | FT_UInt bbox_mode, | |
640 | FT_BBox* cbox ) | |
641 | { | |
642 | const FT_Glyph_Class* clazz; | |
643 | FT_Error error = FT_Err_Ok; | |
644 | ||
645 | ||
646 | if ( !cbox || !glyph || !glyph->clazz ) | |
647 | error = FT_Err_Invalid_Argument; | |
648 | else | |
649 | { | |
650 | clazz = glyph->clazz; | |
651 | if ( !clazz->glyph_bbox ) | |
652 | error = FT_Err_Invalid_Glyph_Format; | |
653 | else | |
654 | { | |
655 | /* retrieve bbox in 26.6 coordinates */ | |
656 | clazz->glyph_bbox( glyph, cbox ); | |
657 | ||
658 | /* perform grid fitting if needed */ | |
659 | if ( bbox_mode & ft_glyph_bbox_gridfit ) | |
660 | { | |
661 | cbox->xMin &= -64; | |
662 | cbox->yMin &= -64; | |
663 | cbox->xMax = ( cbox->xMax + 63 ) & -64; | |
664 | cbox->yMax = ( cbox->yMax + 63 ) & -64; | |
665 | } | |
666 | ||
667 | /* convert to integer pixels if needed */ | |
668 | if ( !( bbox_mode & ft_glyph_bbox_subpixels ) ) | |
669 | { | |
670 | cbox->xMin >>= 6; | |
671 | cbox->yMin >>= 6; | |
672 | cbox->xMax >>= 6; | |
673 | cbox->yMax >>= 6; | |
674 | } | |
675 | } | |
676 | } | |
677 | return; | |
678 | } | |
679 | ||
680 | ||
681 | /*************************************************************************/ | |
682 | /* */ | |
683 | /* <Function> */ | |
684 | /* FT_Glyph_To_Bitmap */ | |
685 | /* */ | |
686 | /* <Description> */ | |
687 | /* Converts a given glyph object to a bitmap glyph object. */ | |
688 | /* */ | |
689 | /* <InOut> */ | |
690 | /* glyph :: A pointer to a handle to the target glyph. */ | |
691 | /* */ | |
692 | /* <Input> */ | |
693 | /* render_mode :: A set of bit flags that describe how the data is */ | |
694 | /* */ | |
695 | /* */ | |
696 | /* origin :: A pointer to a vector used to translate the glyph */ | |
697 | /* image before rendering. Can be 0 (if no */ | |
698 | /* translation). The origin is expressed in */ | |
699 | /* 26.6 pixels. */ | |
700 | /* */ | |
701 | /* destroy :: A boolean that indicates that the original glyph */ | |
702 | /* image should be destroyed by this function. It is */ | |
703 | /* never destroyed in case of error. */ | |
704 | /* */ | |
705 | /* <Return> */ | |
706 | /* FreeType error code. 0 means success. */ | |
707 | /* */ | |
708 | /* <Note> */ | |
709 | /* The glyph image is translated with the `origin' vector before */ | |
710 | /* rendering. In case of error, it it translated back to its */ | |
711 | /* original position and the glyph is left untouched. */ | |
712 | /* */ | |
713 | /* The first parameter is a pointer to a FT_Glyph handle, that will */ | |
714 | /* be replaced by this function. Typically, you would use (omitting */ | |
715 | /* error handling): */ | |
716 | /* */ | |
717 | /* */ | |
718 | /* { */ | |
719 | /* FT_Glyph glyph; */ | |
720 | /* FT_BitmapGlyph glyph_bitmap; */ | |
721 | /* */ | |
722 | /* */ | |
723 | /* // load glyph */ | |
724 | /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ | |
725 | /* */ | |
726 | /* // extract glyph image */ | |
727 | /* error = FT_Get_Glyph( face->glyph, &glyph ); */ | |
728 | /* */ | |
729 | /* // convert to a bitmap (default render mode + destroy old) */ | |
730 | /* if ( glyph->format != ft_glyph_format_bitmap ) */ | |
731 | /* { */ | |
732 | /* error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default, */ | |
733 | /* 0, 1 ); */ | |
734 | /* if ( error ) // glyph unchanged */ | |
735 | /* ... */ | |
736 | /* } */ | |
737 | /* */ | |
738 | /* // access bitmap content by typecasting */ | |
739 | /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ | |
740 | /* */ | |
741 | /* // do funny stuff with it, like blitting/drawing */ | |
742 | /* ... */ | |
743 | /* */ | |
744 | /* // discard glyph image (bitmap or not) */ | |
745 | /* FT_Done_Glyph( glyph ); */ | |
746 | /* } */ | |
747 | /* */ | |
748 | /* */ | |
749 | /* This function will always fail if the glyph's format isn't */ | |
750 | /* scalable. */ | |
751 | /* */ | |
752 | FT_EXPORT_FUNC( FT_Error ) FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, | |
753 | FT_ULong render_mode, | |
754 | FT_Vector* origin, | |
755 | FT_Bool destroy ) | |
756 | { | |
757 | FT_GlyphSlotRec dummy; | |
758 | FT_Error error; | |
759 | FT_Glyph glyph; | |
760 | FT_BitmapGlyph bitmap; | |
761 | ||
762 | const FT_Glyph_Class* clazz; | |
763 | ||
764 | ||
765 | /* check argument */ | |
766 | if ( !the_glyph ) | |
767 | goto Bad; | |
768 | ||
769 | /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ | |
770 | /* then calling FT_Render_Glyph_Internal() */ | |
771 | ||
772 | glyph = *the_glyph; | |
773 | if ( !glyph ) | |
774 | goto Bad; | |
775 | ||
776 | clazz = glyph->clazz; | |
777 | if ( !clazz || !clazz->glyph_prepare ) | |
778 | goto Bad; | |
779 | ||
780 | MEM_Set( &dummy, 0, sizeof ( dummy ) ); | |
781 | dummy.library = glyph->library; | |
782 | dummy.format = clazz->glyph_format; | |
783 | ||
784 | /* if `origin' is set, translate the glyph image */ | |
785 | if ( origin ) | |
786 | FT_Glyph_Transform( glyph, 0, origin ); | |
787 | ||
788 | /* create result bitmap glyph */ | |
789 | error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class, | |
790 | (FT_Glyph*)&bitmap ); | |
791 | if ( error ) | |
792 | goto Exit; | |
793 | ||
794 | /* prepare dummy slot for rendering */ | |
795 | error = clazz->glyph_prepare( glyph, &dummy ) || | |
796 | FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); | |
797 | ||
798 | if ( !destroy && origin ) | |
799 | { | |
800 | FT_Vector v; | |
801 | ||
802 | ||
803 | v.x = -origin->x; | |
804 | v.y = -origin->y; | |
805 | FT_Glyph_Transform( glyph, 0, &v ); | |
806 | } | |
807 | ||
808 | /* in case of succes, copy the bitmap to the glyph bitmap */ | |
809 | if ( !error ) | |
810 | { | |
811 | error = ft_bitmap_glyph_init( bitmap, &dummy ); | |
812 | if ( error ) | |
813 | { | |
814 | /* this should never happen, but let's be safe */ | |
815 | FT_Done_Glyph( FT_GLYPH( bitmap ) ); | |
816 | goto Exit; | |
817 | } | |
818 | ||
819 | if ( destroy ) | |
820 | FT_Done_Glyph( glyph ); | |
821 | ||
822 | *the_glyph = FT_GLYPH( bitmap ); | |
823 | } | |
824 | ||
825 | Exit: | |
826 | return error; | |
827 | ||
828 | Bad: | |
829 | error = FT_Err_Invalid_Argument; | |
830 | goto Exit; | |
831 | } | |
832 | ||
833 | ||
834 | /*************************************************************************/ | |
835 | /* */ | |
836 | /* <Function> */ | |
837 | /* FT_Done_Glyph */ | |
838 | /* */ | |
839 | /* <Description> */ | |
840 | /* Destroys a given glyph. */ | |
841 | /* */ | |
842 | /* <Input> */ | |
843 | /* glyph :: A handle to the target glyph object. */ | |
844 | /* */ | |
845 | FT_EXPORT_FUNC( void ) FT_Done_Glyph( FT_Glyph glyph ) | |
846 | { | |
847 | if ( glyph ) | |
848 | { | |
849 | FT_Memory memory = glyph->library->memory; | |
850 | const FT_Glyph_Class* clazz = glyph->clazz; | |
851 | ||
852 | ||
853 | if ( clazz->glyph_done ) | |
854 | clazz->glyph_done( glyph ); | |
855 | ||
856 | FREE( glyph ); | |
857 | } | |
858 | } | |
859 | ||
860 | ||
861 | #if 0 | |
862 | ||
863 | /*************************************************************************/ | |
864 | /*************************************************************************/ | |
865 | /**** ****/ | |
866 | /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/ | |
867 | /**** ****/ | |
868 | /*************************************************************************/ | |
869 | /*************************************************************************/ | |
870 | ||
871 | /* Compute the norm of a vector */ | |
872 | ||
873 | #ifdef FT_CONFIG_OPTION_OLD_CALCS | |
874 | ||
875 | static | |
876 | FT_Pos ft_norm( FT_Vector* vec ) | |
877 | { | |
878 | FT_Int64 t1, t2; | |
879 | ||
880 | ||
881 | MUL_64( vec->x, vec->x, t1 ); | |
882 | MUL_64( vec->y, vec->y, t2 ); | |
883 | ADD_64( t1, t2, t1 ); | |
884 | ||
885 | return (FT_Pos)SQRT_64( t1 ); | |
886 | } | |
887 | ||
888 | #else /* FT_CONFIG_OPTION_OLD_CALCS */ | |
889 | ||
890 | static | |
891 | FT_Pos ft_norm( FT_Vector* vec ) | |
892 | { | |
893 | FT_F26Dot6 u, v, d; | |
894 | FT_Int shift; | |
895 | FT_ULong H, L, L2, hi, lo, med; | |
896 | ||
897 | ||
898 | u = vec->x; if ( u < 0 ) u = -u; | |
899 | v = vec->y; if ( v < 0 ) v = -v; | |
900 | ||
901 | if ( u < v ) | |
902 | { | |
903 | d = u; | |
904 | u = v; | |
905 | v = d; | |
906 | } | |
907 | ||
908 | /* check that we are not trying to normalize zero! */ | |
909 | if ( u == 0 ) | |
910 | return 0; | |
911 | ||
912 | /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */ | |
913 | hi = (FT_ULong)u >> 16; | |
914 | lo = (FT_ULong)u & 0xFFFF; | |
915 | med = hi * lo; | |
916 | ||
917 | H = hi * hi + ( med >> 15 ); | |
918 | med <<= 17; | |
919 | L = lo * lo + med; | |
920 | if ( L < med ) | |
921 | H++; | |
922 | ||
923 | hi = (FT_ULong)v >> 16; | |
924 | lo = (FT_ULong)v & 0xFFFF; | |
925 | med = hi * lo; | |
926 | ||
927 | H += hi * hi + ( med >> 15 ); | |
928 | med <<= 17; | |
929 | L2 = lo * lo + med; | |
930 | if ( L2 < med ) | |
931 | H++; | |
932 | ||
933 | L += L2; | |
934 | if ( L < L2 ) | |
935 | H++; | |
936 | ||
937 | /* if the value is smaller than 32 bits */ | |
938 | shift = 0; | |
939 | if ( H == 0 ) | |
940 | { | |
941 | while ( ( L & 0xC0000000UL ) == 0 ) | |
942 | { | |
943 | L <<= 2; | |
944 | shift++; | |
945 | } | |
946 | return ( FT_Sqrt32( L ) >> shift ); | |
947 | } | |
948 | else | |
949 | { | |
950 | while ( H ) | |
951 | { | |
952 | L = ( L >> 2 ) | ( H << 30 ); | |
953 | H >>= 2; | |
954 | shift++; | |
955 | } | |
956 | return ( FT_Sqrt32( L ) << shift ); | |
957 | } | |
958 | } | |
959 | ||
960 | #endif /* FT_CONFIG_OPTION_OLD_CALCS */ | |
961 | ||
962 | ||
963 | static | |
964 | int ft_test_extrema( FT_Outline* outline, | |
965 | int n ) | |
966 | { | |
967 | FT_Vector *prev, *cur, *next; | |
968 | FT_Pos product; | |
969 | FT_Int first, last; | |
970 | ||
971 | ||
972 | /* we need to compute the `previous' and `next' point */ | |
973 | /* for these extrema. */ | |
974 | cur = outline->points + n; | |
975 | prev = cur - 1; | |
976 | next = cur + 1; | |
977 | ||
978 | first = 0; | |
979 | for ( c = 0; c < outline->n_contours; c++ ) | |
980 | { | |
981 | last = outline->contours[c]; | |
982 | ||
983 | if ( n == first ) | |
984 | prev = outline->points + last; | |
985 | ||
986 | if ( n == last ) | |
987 | next = outline->points + first; | |
988 | ||
989 | first = last + 1; | |
990 | } | |
991 | ||
992 | product = FT_MulDiv( cur->x - prev->x, /* in.x */ | |
993 | next->y - cur->y, /* out.y */ | |
994 | 0x40 ) | |
995 | - | |
996 | FT_MulDiv( cur->y - prev->y, /* in.y */ | |
997 | next->x - cur->x, /* out.x */ | |
998 | 0x40 ); | |
999 | ||
1000 | if ( product ) | |
1001 | product = product > 0 ? 1 : -1; | |
1002 | ||
1003 | return product; | |
1004 | } | |
1005 | ||
1006 | ||
1007 | /* Compute the orientation of path filling. It differs between TrueType */ | |
1008 | /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */ | |
1009 | /* but it is better to re-compute it directly (it seems that this flag */ | |
1010 | /* isn't correctly set for some weird composite glyphs currently). */ | |
1011 | /* */ | |
1012 | /* We do this by computing bounding box points, and computing their */ | |
1013 | /* curvature. */ | |
1014 | /* */ | |
1015 | /* The function returns either 1 or -1. */ | |
1016 | /* */ | |
1017 | static | |
1018 | int ft_get_orientation( FT_Outline* outline ) | |
1019 | { | |
1020 | FT_BBox box; | |
1021 | FT_BBox indices; | |
1022 | int n, last; | |
1023 | ||
1024 | ||
1025 | indices.xMin = -1; | |
1026 | indices.yMin = -1; | |
1027 | indices.xMax = -1; | |
1028 | indices.yMax = -1; | |
1029 | ||
1030 | box.xMin = box.yMin = 32767; | |
1031 | box.xMax = box.yMax = -32768; | |
1032 | ||
1033 | /* is it empty ? */ | |
1034 | if ( outline->n_contours < 1 ) | |
1035 | return 1; | |
1036 | ||
1037 | last = outline->contours[outline->n_contours - 1]; | |
1038 | ||
1039 | for ( n = 0; n <= last; n++ ) | |
1040 | { | |
1041 | FT_Pos x, y; | |
1042 | ||
1043 | ||
1044 | x = outline->points[n].x; | |
1045 | if ( x < box.xMin ) | |
1046 | { | |
1047 | box.xMin = x; | |
1048 | indices.xMin = n; | |
1049 | } | |
1050 | if ( x > box.xMax ) | |
1051 | { | |
1052 | box.xMax = x; | |
1053 | indices.xMax = n; | |
1054 | } | |
1055 | ||
1056 | y = outline->points[n].y; | |
1057 | if ( y < box.yMin ) | |
1058 | { | |
1059 | box.yMin = y; | |
1060 | indices.yMin = n; | |
1061 | } | |
1062 | if ( y > box.yMax ) | |
1063 | { | |
1064 | box.yMax = y; | |
1065 | indices.yMax = n; | |
1066 | } | |
1067 | } | |
1068 | ||
1069 | /* test orientation of the xmin */ | |
1070 | return ft_test_extrema( outline, indices.xMin ) || | |
1071 | ft_test_extrema( outline, indices.yMin ) || | |
1072 | ft_test_extrema( outline, indices.xMax ) || | |
1073 | ft_test_extrema( outline, indices.yMax ) || | |
1074 | 1; /* this is an empty glyph? */ | |
1075 | } | |
1076 | ||
1077 | ||
1078 | static | |
1079 | FT_Error ft_embolden( FT_Face original, | |
1080 | FT_Outline* outline, | |
1081 | FT_Pos* advance ) | |
1082 | { | |
1083 | FT_Vector u, v; | |
1084 | FT_Vector* points; | |
1085 | FT_Vector cur, prev, next; | |
1086 | FT_Pos distance; | |
1087 | int c, n, first, orientation; | |
1088 | ||
1089 | FT_UNUSED( advance ); | |
1090 | ||
1091 | ||
1092 | /* compute control distance */ | |
1093 | distance = FT_MulFix( original->em_size / 60, | |
1094 | original->size->metrics.y_scale ); | |
1095 | ||
1096 | orientation = ft_get_orientation( &original->glyph->outline ); | |
1097 | ||
1098 | points = original->glyph->outline.points; | |
1099 | ||
1100 | first = 0; | |
1101 | for ( c = 0; c < outline->n_contours; c++ ) | |
1102 | { | |
1103 | int last = outline->contours[c]; | |
1104 | ||
1105 | ||
1106 | prev = points[last]; | |
1107 | ||
1108 | for ( n = first; n <= last; n++ ) | |
1109 | { | |
1110 | FT_Pos norm, delta, d; | |
1111 | FT_Vector in, out; | |
1112 | ||
1113 | ||
1114 | cur = points[n]; | |
1115 | if ( n < last ) next = points[n + 1]; | |
1116 | else next = points[first]; | |
1117 | ||
1118 | /* compute the in and out vectors */ | |
1119 | in.x = cur.x - prev.x; | |
1120 | in.y = cur.y - prev.y; | |
1121 | ||
1122 | out.x = next.x - cur.x; | |
1123 | out.y = next.y - cur.y; | |
1124 | ||
1125 | /* compute U and V */ | |
1126 | norm = ft_norm( &in ); | |
1127 | u.x = orientation * FT_DivFix( in.y, norm ); | |
1128 | u.y = orientation * -FT_DivFix( in.x, norm ); | |
1129 | ||
1130 | norm = ft_norm( &out ); | |
1131 | v.x = orientation * FT_DivFix( out.y, norm ); | |
1132 | v.y = orientation * -FT_DivFix( out.x, norm ); | |
1133 | ||
1134 | d = distance; | |
1135 | ||
1136 | if ( ( outline->flags[n] & FT_Curve_Tag_On ) == 0 ) | |
1137 | d *= 2; | |
1138 | ||
1139 | /* Check discriminant for parallel vectors */ | |
1140 | delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x ); | |
1141 | if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD ) | |
1142 | { | |
1143 | /* Move point -- compute A and B */ | |
1144 | FT_Pos x, y, A, B; | |
1145 | ||
1146 | ||
1147 | A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y ); | |
1148 | B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y ); | |
1149 | ||
1150 | x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y ); | |
1151 | y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x ); | |
1152 | ||
1153 | outline->points[n].x = distance + FT_DivFix( x, delta ); | |
1154 | outline->points[n].y = distance + FT_DivFix( y, delta ); | |
1155 | } | |
1156 | else | |
1157 | { | |
1158 | /* Vectors are nearly parallel */ | |
1159 | FT_Pos x, y; | |
1160 | ||
1161 | ||
1162 | x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2; | |
1163 | y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2; | |
1164 | ||
1165 | outline->points[n].x = x; | |
1166 | outline->points[n].y = y; | |
1167 | } | |
1168 | ||
1169 | prev = cur; | |
1170 | } | |
1171 | ||
1172 | first = last + 1; | |
1173 | } | |
1174 | ||
1175 | if ( advance ) | |
1176 | *advance = ( *advance + distance * 4 ) & -64; | |
1177 | ||
1178 | return 0; | |
1179 | } | |
1180 | ||
1181 | #endif /* 0 -- EXPERIMENTAL STUFF! */ | |
1182 | ||
1183 | ||
1184 | /* END */ |