1 /****************************************************************************/
3 /* The FreeType project -- a free and portable quality TrueType renderer. */
5 /* Copyright 1996-1999 by */
6 /* D. Turner, R.Wilhelm, and W. Lemberg */
8 /* ftstrtto: Making string text from individual glyph information, using */
9 /* TrueType Open features. */
13 /* + : fast scale up */
14 /* - : fast scale down */
15 /* u : fine scale down */
16 /* j : fine scale up */
18 /* h : toggle hinting */
19 /* K : toggle kerning */
27 /* NOTE: This is just a test program that is used to show off and */
28 /* debug the current engine. */
30 /****************************************************************************/
38 #include "common.h" /* for Panic() only */
51 #define MAXPTSIZE 500 /* dtp */
52 #define Center_X ( Bit.width / 2 ) /* dtp */
53 #define Center_Y ( Bit.rows / 2 ) /* dtp */
55 #define FEATURE_init MAKE_TT_TAG( 'i', 'n', 'i', 't' )
56 #define FEATURE_medi MAKE_TT_TAG( 'm', 'e', 'd', 'i' )
57 #define FEATURE_fina MAKE_TT_TAG( 'f', 'i', 'n', 'a' )
58 #define FEATURE_isol MAKE_TT_TAG( 'i', 's', 'o', 'l' )
75 TT_Big_Glyph_Metrics metrics
;
77 TT_Face_Properties face_properties
;
78 TT_Instance_Metrics imetrics
;
96 TT_Bool glyph_has_sbit
;
98 TT_Bool default_language_system
;
104 TT_UShort glyph_code_array
[129];
105 TT_UShort char_code
[128];
106 TT_UShort properties
[128];
108 TT_UShort
* glyph_code
;
112 char* script_tag_string
;
113 TT_UShort script_index
;
115 TT_ULong language_tag
;
116 char* language_tag_string
;
117 TT_UShort language_index
;
118 TT_UShort req_feature_index
= 0xFFFF;
120 TT_ULong
* feature_tags
;
121 char** feature_tag_strings
;
122 TT_UShort
* feature_indices
;
126 static void Select_CMap( void )
129 TT_UShort platform
, encoding
;
132 n
= face_properties
.num_CharMaps
;
134 for ( i
= 0; i
< n
; i
++ )
136 TT_Get_CharMap_ID( face
, i
, &platform
, &encoding
);
137 if ( platform
== 3 && encoding
== 1 )
139 TT_Get_CharMap( face
, i
, &char_map
);
144 /* we try only pid/eid (0,0) if no (3,1) map is found -- many Windows
145 fonts have only rudimentary (0,0) support. */
149 for ( i
= 0; i
< n
; i
++ )
151 TT_Get_CharMap_ID( face
, i
, &platform
, &encoding
);
152 if ( platform
== 0 && encoding
== 0 )
154 TT_Get_CharMap( face
, i
, &char_map
);
160 Panic( "Sorry, but this font doesn't contain"
161 " any Unicode mapping table\n" );
166 /* Convert a Latin 1 string to a string of glyph indexes. */
168 /* IMPORTANT NOTE: */
170 /* There is no portable way to convert from any system's char. code */
171 /* to Unicode. This function simply takes a char. string as argument */
172 /* and `interprets' each character as a Unicode char. index with no */
175 /* We interpret the command line string as Unicode with the high byte */
176 /* set to zero. This is equivalent to Latin-1. */
178 static void Latin1Char_To_Glyph( char* source
)
183 glyph_code
= glyph_code_array
+ 1; /* we want to make glyph_code[-1] */
184 glyph_code
[-1] = 0; /* possible. */
186 for ( n
= 0; n
< 128 && source
[n
]; n
++ )
188 char_code
[n
] = (TT_UShort
)( (unsigned char)source
[n
] );
189 glyph_code
[n
] = TT_Char_Index( char_map
, char_code
[n
] );
196 static void UTF8Char_To_Glyph( char* source
)
198 TT_UShort in
, out
, in_code
, out_code
;
199 TT_UShort count
, limit
;
202 glyph_code
= glyph_code_array
+ 1; /* we want to make glyph_code[-1] */
203 glyph_code
[-1] = 0; /* possible. */
205 for ( in
= out
= 0, count
= limit
= 1, in_code
= out_code
= 0;
206 in
< 128 && source
[in
]; in
++ )
208 in_code
= (TT_UShort
)( (unsigned char)source
[in
] );
210 if ( in_code
>= 0xC0 )
215 if ( in_code
< 0xE0 ) /* U+0080 - U+07FF */
218 out_code
= in_code
& 0x1F;
220 else if ( in_code
< 0xF0 ) /* U+0800 - U+FFFF */
223 out_code
= in_code
& 0x0F;
227 else if ( in_code
>= 0x80 )
231 if ( count
<= limit
)
234 out_code
+= in_code
& 0x3F;
236 if ( count
!= limit
)
242 char_code
[out
] = out_code
;
243 glyph_code
[out
++] = TT_Char_Index( char_map
, out_code
);
250 static TT_Error
Reset_Scale( int pointSize
)
255 error
= TT_Set_Instance_CharSize( instance
, pointSize
* 64L );
259 Panic( "Could not reset instance, code = 0x%x.\n", error
);
262 TT_Get_Instance_Metrics( instance
, &imetrics
);
264 /* now re-allocate the small bitmap */
267 Init_Small( imetrics
.x_ppem
, imetrics
.y_ppem
);
275 static TT_Error
Load_TrueType_Char( TT_UShort idx
,
284 error
= TT_Load_Glyph_Bitmap( face
, instance
, idx
, sbit
);
285 if ( error
== TT_Err_Ok
)
291 if ( glyph_has_sbit
&& use_sbit
)
294 flags
= TTLOAD_SCALE_GLYPH
;
296 flags
|= TTLOAD_HINT_GLYPH
;
298 return TT_Load_Glyph( instance
, glyph
, idx
, flags
);
302 static TT_Error
Get_Kern_Values( TT_UShort idx
,
307 TT_Kern_Subtable table
;
308 TT_Kern_0_Pair
* pairs_0
;
310 TT_UShort min
, max
, new_min
, new_max
, middle
;
311 TT_Long target_idx
, current_idx
;
317 for ( i
= 0; i
< directory
.nTables
; i
++ )
319 table
= directory
.tables
[i
];
321 /* handle only horizontal kerning tables */
323 if ( table
.coverage
& 0x0001 )
325 switch ( table
.format
)
328 pairs_0
= table
.t
.kern0
.pairs
;
329 target_idx
= ( glyph_code
[idx
- 1] << 16 ) + glyph_code
[idx
];
334 new_max
= table
.t
.kern0
.nPairs
- 1;
340 middle
= max
- ( ( max
- min
) >> 1 );
342 current_idx
= ( pairs_0
[middle
].left
<< 16 ) +
343 pairs_0
[middle
].right
;
345 if ( target_idx
== current_idx
)
347 *x
+= pairs_0
[middle
].value
;
350 else if ( target_idx
< current_idx
)
354 new_max
= middle
- 1;
360 new_min
= middle
+ 1;
362 } while ( min
< max
);
366 /* we currently ignore format 2 kerning tables */
374 /* scaling and rounding */
376 *x
= ( ( ( *x
* imetrics
.x_scale
) / 0x10000 ) + 32 ) & -64;
377 *y
= ( ( ( *y
* imetrics
.y_scale
) / 0x10000 ) + 32 ) & -64;
383 /* for testing purposes, we always select the last available alternate
384 glyph, not using the `data' field. */
386 static TT_UShort
alternate_function( TT_ULong pos
,
388 TT_UShort num_alternates
,
389 TT_UShort
* alternates
,
392 return num_alternates
- 1;
396 static TT_Error
Render_All( void )
398 TT_Pos x
, y
, z
, min_x
, min_y
, max_x
, max_y
;
399 TT_Pos kern_x
, kern_y
;
402 TT_UShort glyph_property
= 0;
406 TTO_GSUB_String in
, out
;
409 /* On the first pass, we compute the compound bounding box */
413 min_x
= min_y
= max_x
= max_y
= 0;
415 in
.length
= num_glyphs
;
417 in
.string
= glyph_code
;
418 in
.properties
= properties
;
423 out
.properties
= NULL
;
425 if ( has_gsub
&& use_gsub
)
427 error
= TT_GSUB_Apply_String( gsub
, &in
, &out
);
428 if ( error
&& error
!= TTO_Err_Not_Covered
)
442 for ( i
= 0; i
< n
; i
++ )
444 error
= Load_TrueType_Char( gc
[i
], hinted
);
445 if ( error
== TT_Err_Ok
)
447 if ( glyph_has_sbit
&& use_sbit
)
448 metrics
= sbit
->metrics
;
450 TT_Get_Glyph_Big_Metrics( glyph
, &metrics
);
451 if ( has_kern
&& use_kern
)
452 Get_Kern_Values( i
, &kern_x
, &kern_y
);
454 z
= x
+ metrics
.bbox
.xMin
+ kern_x
;
458 z
= x
+ metrics
.bbox
.xMax
+ kern_x
;
462 z
= y
+ metrics
.bbox
.yMin
+ kern_y
;
466 z
= y
+ metrics
.bbox
.yMax
+ kern_y
;
472 error
= TT_GDEF_Get_Glyph_Property( gdef
, gc
[i
], &glyph_property
);
477 /* advance only if it is not a mark glyph */
479 if ( !( glyph_property
& TTO_MARK
) )
482 y
+= ( metrics
.vertAdvance
& -64 ) + kern_y
;
484 x
+= ( metrics
.horiAdvance
& -64 ) + kern_x
;
491 /* We now center the bbox inside the target bitmap */
493 min_x
= ( min_x
& -64 ) >> 6;
494 min_y
= ( min_y
& -64 ) >> 6;
496 max_x
= ( (max_x
+ 63) & -64 ) >> 6;
497 max_y
= ( (max_y
+ 63) & -64 ) >> 6;
502 min_x
= ( Bit
.width
- max_x
) / 2;
503 min_y
= ( Bit
.rows
- max_y
) / 2;
508 /* On the second pass, we render each glyph to its centered position. */
509 /* This is slow, because we reload each glyph to render it! */
511 x
= vertical
? min_x
: ( r2l
? max_x
: min_x
);
512 y
= vertical
? ( r2l
? min_y
: max_y
) : min_y
;
514 for ( i
= 0; i
< n
; i
++ )
516 error
= Load_TrueType_Char( gc
[i
], hinted
);
517 if ( error
== TT_Err_Ok
)
519 if ( glyph_has_sbit
&& use_sbit
)
520 metrics
= sbit
->metrics
;
522 TT_Get_Glyph_Big_Metrics( glyph
, &metrics
);
523 if ( has_kern
&& use_kern
)
524 Get_Kern_Values( i
, &kern_x
, &kern_y
);
527 (void)TT_GDEF_Get_Glyph_Property( gdef
, gc
[i
], &glyph_property
);
529 if ( !( glyph_property
& TTO_MARK
) )
534 y
+= metrics
.vertAdvance
/ 64;
536 x
-= metrics
.horiAdvance
/ 64;
547 /* We must specify the upper left corner of the bitmap, but the
548 lower left corner for the outline. Another complication is that
549 Blit_Bitmap() assumes that increasing y values means moving
552 For vertical layout, the origin of the horizontal and vertical
553 bearings of embedded bitmaps is the top, thus we shift the
554 outline glyphs down. */
556 if ( glyph_has_sbit
&& use_sbit
)
561 ( vertical
? metrics
.vertBearingX
:
562 metrics
.horiBearingX
) / 64,
564 ( vertical
? metrics
.vertBearingY
:
565 metrics
.horiBearingY
) / 64,
573 ( vertical
? metrics
.vertBearingY
+ metrics
.bbox
.yMax
:
576 if ( !( glyph_property
& TTO_MARK
) )
588 y
-= metrics
.vertAdvance
/ 64;
590 x
+= metrics
.horiAdvance
/ 64;
598 if ( out
.properties
)
599 free( out
.properties
);
605 static int Process_Event( TEvent
* event
)
607 switch ( event
->what
)
609 case event_Quit
: /* ESC or q */
613 if ( event
->info
== 'h' ) /* Toggle hinting */
615 else if ( event
->info
== 'K' ) /* Toggle kerning */
616 use_kern
= !use_kern
;
617 else if ( event
->info
== 'B' ) /* Toggle sbit */
618 use_sbit
= !use_sbit
;
619 else if ( event
->info
== 'G' ) /* Toggle gsub */
620 use_gsub
= !use_gsub
;
623 case event_Rotate_Glyph
:
626 case event_Scale_Glyph
:
627 pt_size
+= event
->info
;
628 if ( pt_size
< 1 ) pt_size
= 1;
629 if ( pt_size
> MAXPTSIZE
) pt_size
= MAXPTSIZE
;
632 case event_Change_Glyph
:
640 static void Usage( char* execname
)
644 "ftstrtto: TrueType Open String Test Display -- part of the FreeType project\n"
645 "---------------------------------------------------------------------------\n"
647 "Usage: %s [options below] ppem fontname[.ttf|.ttc] [string|-]\n"
649 " -c C use font with index C in TrueType collection (default: 0)\n"
650 " -f F use feature F (can be specified more than once)\n"
651 " -g gray-level rendering\n"
652 " -l L use language L\n"
653 " -r R use resolution R dpi (default: 96)\n"
654 " -s S use script S\n"
655 " -u interpret input data as UTF8-encoded\n"
656 " -v display string vertically\n"
657 " -x display string from right to left\n"
659 " F, L, and S must be specified as 4-character tags.\n"
660 " Specifying only F and S selects default language system of S.\n"
661 " Specifying only L and S selects the req. feature of L only (if any).\n"
663 " If `-' is specified as input string, stdin is read instead.\n"
666 exit( EXIT_FAILURE
);
670 static TT_ULong
Make_Tag( char* tag_string
)
672 char t1
= ' ', t2
= ' ', t3
= ' ', t4
= ' ';
686 return MAKE_TT_TAG( t1
, t2
, t3
, t4
);
693 int i
, old_pt_size
, orig_pt_size
, file
;
695 int graphics_initialized
= 0;
697 char filename
[128 + 4];
698 char alt_filename
[128 + 4];
713 option
= ft_getopt( argc
, argv
, "c:f:gl:r:s:uvx" );
721 ttc_index
= atoi( ft_optarg
);
728 feature_tag_strings
= (char**)
729 realloc( feature_tag_strings
,
730 num_features
* sizeof ( char* ) );
731 feature_tags
= (TT_ULong
*)
732 realloc( feature_tags
,
733 num_features
* sizeof ( TT_ULong
) );
734 feature_tag_strings
[num_features
- 1] = ft_optarg
;
735 if ( !(feature_tags
[num_features
- 1] = Make_Tag( ft_optarg
) ) )
744 language_tag_string
= ft_optarg
;
745 if ( !(language_tag
= Make_Tag( ft_optarg
) ) )
750 res
= atoi( ft_optarg
);
756 script_tag_string
= ft_optarg
;
757 if ( !(script_tag
= Make_Tag( ft_optarg
) ) )
785 if ( sscanf( argv
[0], "%d", &orig_pt_size
) != 1 )
790 /* Initialize engine */
792 error
= TT_Init_FreeType( &engine
);
794 Panic( "Error while initializing engine, code = 0x%x.\n", error
);
796 error
= TT_Init_Kerning_Extension( engine
);
798 Panic( "Error while initializing kerning extension, code = 0x%x.\n",
801 error
= TT_Init_SBit_Extension( engine
);
803 Panic( "Error while initializing sbit extension, code = 0x%x.\n",
806 error
= TT_Init_GDEF_Extension( engine
);
808 Panic( "Error while initializing GDEF extension, code = 0x%x.\n",
811 error
= TT_Init_GSUB_Extension( engine
);
813 Panic( "Error while initializing GSUB extension, code = 0x%x.\n",
816 pt_size
= orig_pt_size
;
822 i
= strlen( argv
[file
] );
823 while ( i
> 0 && argv
[file
][i
] != '\\' && argv
[file
][i
] != '/' )
825 if ( argv
[file
][i
] == '.' )
830 filename
[128] = '\0';
831 alt_filename
[128] = '\0';
833 strncpy( filename
, argv
[file
], 128 );
834 strncpy( alt_filename
, argv
[file
], 128 );
838 strncpy( filename
+ strlen( filename
), ".ttf", 4 );
839 strncpy( alt_filename
+ strlen( alt_filename
), ".ttc", 4 );
844 error
= TT_Open_Face( engine
, filename
, &face
);
845 if ( error
== TT_Err_Could_Not_Open_File
)
847 strcpy( filename
, alt_filename
);
848 error
= TT_Open_Face( engine
, alt_filename
, &face
);
850 if ( error
== TT_Err_Could_Not_Open_File
)
851 Panic( "Could not find/open `%s'.\n", filename
);
853 Panic( "Error while opening `%s', code = 0x%x.\n",
856 /* get face properties and allocate preload arrays */
858 TT_Get_Face_Properties( face
, &face_properties
);
860 /* open font in collection */
862 if ( ttc_index
>= face_properties
.num_Faces
)
863 Panic( "There is no collection with index %d in this font file.\n",
866 TT_Close_Face( face
);
868 error
= TT_Open_Collection( engine
, filename
, ttc_index
, &face
);
870 Panic( "Error while opening collection %d in `%s', code = 0x%x.\n",
871 ttc_index
, filename
, error
);
875 error
= TT_New_Glyph( face
, &glyph
);
877 Panic( "Could not create glyph container, code = 0x%x.\n", error
);
879 /* create sbit slot */
881 error
= TT_New_SBit_Image( &sbit
);
883 Panic( "Could not create sbit slot, code = 0x%x.\n" , error
);
885 /* create instance */
887 error
= TT_New_Instance( face
, &instance
);
889 Panic( "Could not create instance for `%s', code = 0x%x.\n",
892 error
= TT_Set_Instance_Resolutions( instance
, res
, res
);
894 Panic( "Could not set device resolutions, code = 0x%x.\n", error
);
896 error
= TT_Get_Kerning_Directory( face
, &directory
);
898 Panic( "Could not get kerning directory, code = 0x%x.\n", error
);
900 /* load all kerning tables */
902 for ( i
= 0; i
< directory
.nTables
; i
++ )
904 error
= TT_Load_Kerning_Table( face
, i
);
906 Panic( "Could not load kerning table, code = 0x%x.\n", error
);
909 if ( directory
.nTables
)
918 error
= TT_Load_GDEF_Table( face
, gdef
);
921 else if ( error
!= TT_Err_Table_Missing
)
922 Panic( "Error while loading GDEF table, code = 0x%x.\n", error
);
924 /* we must assign glyph properties in case no GDEF table is available */
928 Build_Arabic_Glyph_Properties( char_map
, face_properties
.num_Glyphs
,
938 error
= TT_Load_GSUB_Table( face
, gsub
, gdef
);
941 if ( script_tag
&& feature_tags
)
943 if ( script_tag
&& language_tag
)
946 else if ( error
!= TT_Err_Table_Missing
)
947 Panic( "Error while loading GSUB table, code = 0x%x.\n", error
);
949 TT_GSUB_Clear_Features( gsub
);
951 if ( has_gsub
&& !language_tag
)
952 default_language_system
= 1;
954 feature_indices
= (TT_UShort
*)
955 malloc( num_features
* sizeof ( TT_UShort
) );
959 error
= TT_GSUB_Select_Script( gsub
,
963 Panic( "Requested script `%-4.4s' not found.\n",
966 if ( default_language_system
)
968 for ( i
= 0; i
< num_features
; i
++ )
970 error
= TT_GSUB_Select_Feature( gsub
,
972 script_index
, 0xFFFF,
973 &feature_indices
[i
] );
975 Panic( "Requested feature `%-4.4s'\n"
976 "for default language system of script `%-4.4s' not found.\n",
977 feature_tag_strings
[i
], script_tag_string
);
982 error
= TT_GSUB_Select_Language( gsub
,
986 &req_feature_index
);
988 Panic( "Requested language `%-4.4s'\n"
989 "for script `%-4.4s' not found.\n",
990 language_tag_string
, script_tag_string
);
992 for ( i
= 0; i
< num_features
; i
++ )
994 error
= TT_GSUB_Select_Feature( gsub
,
996 script_index
, language_index
,
997 &feature_indices
[i
] );
999 Panic( "Requested feature `%-4.4s'\n"
1000 "for script `%-4.4s', language `%-4.4s' not found.\n",
1001 feature_tag_strings
[i
], script_tag_string
,
1002 language_tag_string
);
1006 if ( req_feature_index
!= 0xFFFF )
1007 TT_GSUB_Add_Feature( gsub
, req_feature_index
, ALL_GLYPHS
);
1008 else if ( !num_features
)
1011 for ( i
= 0; i
< num_features
; i
++ )
1013 if ( feature_tags
[i
] == FEATURE_init
)
1014 TT_GSUB_Add_Feature( gsub
, feature_indices
[i
], initial
);
1015 else if ( feature_tags
[i
] == FEATURE_medi
)
1016 TT_GSUB_Add_Feature( gsub
, feature_indices
[i
], medial
);
1017 else if ( feature_tags
[i
] == FEATURE_fina
)
1018 TT_GSUB_Add_Feature( gsub
, feature_indices
[i
], final
);
1019 else if ( feature_tags
[i
] == FEATURE_isol
)
1020 TT_GSUB_Add_Feature( gsub
, feature_indices
[i
], isolated
);
1022 TT_GSUB_Add_Feature( gsub
, feature_indices
[i
], ALL_GLYPHS
);
1025 TT_GSUB_Register_Alternate_Function( gsub
, alternate_function
, NULL
);
1029 if ( !graphics_initialized
)
1031 graphics_initialized
= 1;
1035 if ( !SetGraphScreen( Graphics_Mode_Gray
) )
1036 Panic( "Could not set up grayscale graphics mode.\n" );
1038 TT_Set_Raster_Gray_Palette( engine
, virtual_palette
);
1042 if ( !SetGraphScreen( Graphics_Mode_Mono
) )
1043 Panic( "Could not set up mono graphics mode.\n" );
1047 Init_Display( gray_render
);
1049 Reset_Scale( pt_size
);
1051 old_pt_size
= pt_size
;
1055 /* get string to display, if any */
1059 if ( argv
[2][0] == '-' )
1065 char_string
= (char*)malloc( 128 * sizeof ( char ) );
1068 for ( i
= 0; i
< 128; i
++ )
1071 if ( ch
== '\n' || ch
== EOF
)
1083 char_string
= argv
[2];
1086 char_string
= "The quick brown fox jumps over the lazy dog";
1089 UTF8Char_To_Glyph( char_string
);
1091 Latin1Char_To_Glyph( char_string
);
1093 /* we assign Arabic script features (e.g. `initial' or `final') */
1095 Assign_Arabic_Properties( char_code
, properties
, num_glyphs
);
1104 error
= Render_All();
1106 Panic( "Error while rendering string, code = 0x%x.\n", error
);
1109 Convert_To_Display_Palette();
1112 "%s: ptsize: %d hinting: %s%s%s%s%s%s%s",
1113 ft_basename( filename
),
1115 hinted
? "on" : "off",
1116 has_kern
? " kerning: " : "",
1117 has_kern
? ( use_kern
? "on" : "off" ) : "",
1118 has_sbit
? " sbit: " : "",
1119 has_sbit
? ( use_sbit
? "on" : "off" ) : "",
1120 has_gsub
? " GSUB: " : "",
1121 has_gsub
? ( use_gsub
? "on" : "off" ) : "" );
1123 Display_Bitmap_On_Screen( Bit
.bitmap
, Bit
.rows
, Bit
.cols
);
1127 Print_XY( 0, 0, Header
);
1131 Get_Event( &event
);
1132 if ( !( key
= Process_Event( &event
) ) )
1135 if ( pt_size
!= old_pt_size
)
1137 if ( Reset_Scale( pt_size
) )
1138 Panic( "Could not resize font.\n" );
1140 old_pt_size
= pt_size
;
1147 TT_Done_FreeType( engine
);
1149 printf( "Execution completed successfully.\n" );
1150 printf( "Fails = %d.\n", Fail
);
1152 exit( EXIT_SUCCESS
); /* for safety reasons */
1154 return 0; /* never reached */