... |
... |
@@ -24,6 +24,7 @@ |
24
|
24
|
#include <freetype/tttags.h>
|
25
|
25
|
#include <freetype/t1tables.h>
|
26
|
26
|
|
|
27
|
+#include <freetype/ftcid.h>
|
27
|
28
|
|
28
|
29
|
/* error messages */
|
29
|
30
|
#undef FTERRORS_H_
|
... |
... |
@@ -114,7 +115,7 @@ |
114
|
115
|
execname );
|
115
|
116
|
|
116
|
117
|
fprintf( stderr,
|
117
|
|
- " -c, -C Print charmap coverage.\n"
|
|
118
|
+ " -c, -C Print charmap coverage and/or CID coverage.\n"
|
118
|
119
|
" -n Print SFNT 'name' table or Type1 font info.\n"
|
119
|
120
|
" -p Print TrueType programs.\n"
|
120
|
121
|
" -t Print SFNT table list.\n"
|
... |
... |
@@ -480,6 +481,132 @@ |
480
|
481
|
}
|
481
|
482
|
|
482
|
483
|
|
|
484
|
+ /*
|
|
485
|
+ * FreeType 2 API supports 32-bit gid, but
|
|
486
|
+ * the CIDFont does not support 32-bit CID,
|
|
487
|
+ * because of the 64k limit of the array
|
|
488
|
+ * and dictionary objects in PostScript.
|
|
489
|
+ */
|
|
490
|
+#ifndef FT_CID_MAX
|
|
491
|
+#define FT_CID_MAX 0xFFFFU
|
|
492
|
+#endif
|
|
493
|
+ /*
|
|
494
|
+ * Print a range specified by 2 integers.
|
|
495
|
+ */
|
|
496
|
+ static void
|
|
497
|
+ Print_UInt_Range( FT_UInt from,
|
|
498
|
+ FT_UInt to,
|
|
499
|
+ char* is_first )
|
|
500
|
+ {
|
|
501
|
+ if (!(*is_first))
|
|
502
|
+ printf(",");
|
|
503
|
+
|
|
504
|
+ if ( from == to )
|
|
505
|
+ printf( "%d", from );
|
|
506
|
+ else if ( from < to )
|
|
507
|
+ printf( "%d-%d", from, to );
|
|
508
|
+
|
|
509
|
+ *is_first = 0;
|
|
510
|
+ }
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+ /*
|
|
514
|
+ * Print implemented CIDs by calling
|
|
515
|
+ * FT_Get_CID_From_Glyph_Index() for all GIDs.
|
|
516
|
+ *
|
|
517
|
+ */
|
|
518
|
+ static void
|
|
519
|
+ Print_CIDs( FT_Face face )
|
|
520
|
+ {
|
|
521
|
+ FT_UInt gid = 0, max_gid = FT_UINT_MAX;
|
|
522
|
+ FT_UInt cid = 0, rng_from = 0, rng_to = 0;
|
|
523
|
+ char is_first_rng = 1;
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+ if ( face->num_glyphs < 1 )
|
|
527
|
+ return;
|
|
528
|
+
|
|
529
|
+ printf( "\n" );
|
|
530
|
+ printf( "CID coverage\n" );
|
|
531
|
+ printf( " " );
|
|
532
|
+
|
|
533
|
+ if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX )
|
|
534
|
+ max_gid = (FT_UInt)face->num_glyphs;
|
|
535
|
+
|
|
536
|
+ for ( gid = 0; gid <= max_gid; gid ++ )
|
|
537
|
+ {
|
|
538
|
+ if ( FT_Get_CID_From_Glyph_Index( face, gid, &cid ) )
|
|
539
|
+ continue;
|
|
540
|
+
|
|
541
|
+ if ( FT_CID_MAX < cid )
|
|
542
|
+ {
|
|
543
|
+ fprintf( stderr, "gid=%d resulted too large CID=%d, ignore it\n", gid, cid );
|
|
544
|
+ break;
|
|
545
|
+ }
|
|
546
|
+
|
|
547
|
+ if ( rng_to == cid )
|
|
548
|
+ continue;
|
|
549
|
+ else if ( cid < rng_to )
|
|
550
|
+ {
|
|
551
|
+ fprintf( stderr, "Unordered GID-CID map is found, please file your issue on "
|
|
552
|
+ "https://gitlab.freedesktop.org/groups/freetype/-/issues\n" );
|
|
553
|
+ exit( 1 );
|
|
554
|
+ }
|
|
555
|
+ else if ( rng_to + 1 == cid )
|
|
556
|
+ {
|
|
557
|
+ rng_to = cid;
|
|
558
|
+ continue;
|
|
559
|
+ }
|
|
560
|
+
|
|
561
|
+ /* Found a gap (rng_to + 1 < cid), print the last range */
|
|
562
|
+ Print_UInt_Range( rng_from, rng_to, &is_first_rng );
|
|
563
|
+ rng_to = rng_from = cid;
|
|
564
|
+ }
|
|
565
|
+
|
|
566
|
+ Print_UInt_Range( rng_from, rng_to, &is_first_rng );
|
|
567
|
+
|
|
568
|
+ printf( "\n" );
|
|
569
|
+ }
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+ /*
|
|
573
|
+ * Print_CIDFontInfo_Dictionary() might be conventional,
|
|
574
|
+ * but other tables, like gcid, can have ROS info too.
|
|
575
|
+ */
|
|
576
|
+ static void
|
|
577
|
+ Print_ROS_From_Face( FT_Face face )
|
|
578
|
+ {
|
|
579
|
+ FT_Bool is_cid = 0;
|
|
580
|
+ const char* r = NULL;
|
|
581
|
+ const char* o = NULL;
|
|
582
|
+ FT_Int s = -1;
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+ if ( FT_Get_CID_Is_Internally_CID_Keyed( face, &is_cid ) )
|
|
586
|
+ return;
|
|
587
|
+
|
|
588
|
+ if ( !is_cid )
|
|
589
|
+ return;
|
|
590
|
+
|
|
591
|
+ if ( FT_Get_CID_Registry_Ordering_Supplement( face, &r, &o, &s ) )
|
|
592
|
+ return;
|
|
593
|
+
|
|
594
|
+ printf( "\n" );
|
|
595
|
+ printf( "/CIDSystemInfo dictionary\n" );
|
|
596
|
+
|
|
597
|
+ if ( r )
|
|
598
|
+ printf( "%s%s\n", Name_Field( "Registry" ), r );
|
|
599
|
+
|
|
600
|
+ if ( o )
|
|
601
|
+ printf( "%s%s\n", Name_Field( "Ordering" ), o );
|
|
602
|
+
|
|
603
|
+ printf( "%s%d\n", Name_Field( "Supplement" ), s );
|
|
604
|
+
|
|
605
|
+ if ( coverage > 0 )
|
|
606
|
+ Print_CIDs( face );
|
|
607
|
+ }
|
|
608
|
+
|
|
609
|
+
|
483
|
610
|
static void
|
484
|
611
|
Print_FontPrivate_Dictionary( PS_Private fp )
|
485
|
612
|
{
|
... |
... |
@@ -560,7 +687,7 @@ |
560
|
687
|
else
|
561
|
688
|
continue;
|
562
|
689
|
|
563
|
|
- printf( " %2lu: %c%c%c%c %02X%02X%02X%02X...\n", i,
|
|
690
|
+ printf( " %2lu: %c%c%c%c %02X %02X %02X %02X ...\n", i,
|
564
|
691
|
(FT_Char)( tag >> 24 ),
|
565
|
692
|
(FT_Char)( tag >> 16 ),
|
566
|
693
|
(FT_Char)( tag >> 8 ),
|
... |
... |
@@ -711,19 +838,53 @@ |
711
|
838
|
|
712
|
839
|
|
713
|
840
|
static void
|
714
|
|
- Print_MM_Axes( FT_Face face )
|
|
841
|
+ get_english_name_entry( FT_Face face,
|
|
842
|
+ FT_UInt strid,
|
|
843
|
+ FT_SfntName* entry )
|
|
844
|
+ {
|
|
845
|
+ FT_UInt num_names = FT_Get_Sfnt_Name_Count( face );
|
|
846
|
+ FT_UInt i;
|
|
847
|
+
|
|
848
|
+ FT_SfntName name;
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+ for ( i = 0; i < num_names; i++ )
|
|
852
|
+ {
|
|
853
|
+ error = FT_Get_Sfnt_Name( face, i, &name );
|
|
854
|
+ if ( error )
|
|
855
|
+ continue;
|
|
856
|
+
|
|
857
|
+ if ( name.name_id == strid )
|
|
858
|
+ {
|
|
859
|
+ /* XXX we don't have support for Apple's new `ltag' table yet, */
|
|
860
|
+ /* thus we ignore TT_PLATFORM_APPLE_UNICODE */
|
|
861
|
+ if ( ( name.platform_id == TT_PLATFORM_MACINTOSH &&
|
|
862
|
+ name.language_id == TT_MAC_LANGID_ENGLISH ) ||
|
|
863
|
+ ( name.platform_id == TT_PLATFORM_MICROSOFT &&
|
|
864
|
+ ( name.language_id & 0xFF )
|
|
865
|
+ == TT_MS_LANGID_ENGLISH_GENERAL ) )
|
|
866
|
+ break;
|
|
867
|
+ }
|
|
868
|
+ }
|
|
869
|
+
|
|
870
|
+ if ( i < num_names )
|
|
871
|
+ *entry = name;
|
|
872
|
+ }
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+ static void
|
|
876
|
+ Print_MM_Info( FT_Face face )
|
715
|
877
|
{
|
716
|
878
|
FT_MM_Var* mm;
|
717
|
879
|
FT_Multi_Master dummy;
|
718
|
|
- FT_UInt is_GX, i, num_names;
|
|
880
|
+ FT_SfntName name;
|
|
881
|
+ FT_UInt is_GX, i;
|
719
|
882
|
|
720
|
883
|
|
721
|
884
|
/* MM or GX axes */
|
722
|
885
|
error = FT_Get_Multi_Master( face, &dummy );
|
723
|
886
|
is_GX = error ? 1 : 0;
|
724
|
887
|
|
725
|
|
- printf( "%s axes\n", is_GX ? "GX" : "MM" );
|
726
|
|
-
|
727
|
888
|
error = FT_Get_MM_Var( face, &mm );
|
728
|
889
|
if ( error )
|
729
|
890
|
{
|
... |
... |
@@ -731,60 +892,134 @@ |
731
|
892
|
return;
|
732
|
893
|
}
|
733
|
894
|
|
734
|
|
- num_names = FT_Get_Sfnt_Name_Count( face );
|
|
895
|
+ printf( "%s info\n", is_GX ? "GX" : "MM" );
|
|
896
|
+
|
|
897
|
+ printf( " axes (%u)\n", mm->num_axis );
|
735
|
898
|
|
736
|
899
|
for ( i = 0; i < mm->num_axis; i++ )
|
737
|
900
|
{
|
738
|
|
- FT_SfntName name;
|
739
|
|
-
|
740
|
|
-
|
741
|
901
|
name.string = NULL;
|
742
|
902
|
|
743
|
903
|
if ( is_GX )
|
744
|
|
- {
|
745
|
|
- FT_UInt strid = mm->axis[i].strid;
|
746
|
|
- FT_UInt j;
|
747
|
|
-
|
748
|
|
-
|
749
|
|
- /* iterate over all name entries */
|
750
|
|
- /* to find an English entry for `strid' */
|
751
|
|
-
|
752
|
|
- for ( j = 0; j < num_names; j++ )
|
753
|
|
- {
|
754
|
|
- error = FT_Get_Sfnt_Name( face, j, &name );
|
755
|
|
- if ( error )
|
756
|
|
- continue;
|
757
|
|
-
|
758
|
|
- if ( name.name_id == strid )
|
759
|
|
- {
|
760
|
|
- /* XXX we don't have support for Apple's new `ltag' table yet, */
|
761
|
|
- /* thus we ignore TT_PLATFORM_APPLE_UNICODE */
|
762
|
|
- if ( ( name.platform_id == TT_PLATFORM_MACINTOSH &&
|
763
|
|
- name.language_id == TT_MAC_LANGID_ENGLISH ) ||
|
764
|
|
- ( name.platform_id == TT_PLATFORM_MICROSOFT &&
|
765
|
|
- ( name.language_id & 0xFF )
|
766
|
|
- == TT_MS_LANGID_ENGLISH_GENERAL ) )
|
767
|
|
- break;
|
768
|
|
- }
|
769
|
|
- }
|
770
|
|
- }
|
|
904
|
+ get_english_name_entry( face, mm->axis[i].strid, &name );
|
771
|
905
|
|
|
906
|
+ printf( " %u: ", i );
|
772
|
907
|
if ( name.string )
|
773
|
908
|
{
|
774
|
909
|
if ( name.platform_id == TT_PLATFORM_MACINTOSH )
|
775
|
|
- put_ascii( name.string, name.string_len, 3 );
|
|
910
|
+ put_ascii( name.string, name.string_len, 0 );
|
776
|
911
|
else
|
777
|
|
- put_unicode_be16( name.string, name.string_len, 3, utf8 );
|
|
912
|
+ put_unicode_be16( name.string, name.string_len, 0, utf8 );
|
778
|
913
|
}
|
779
|
914
|
else
|
780
|
|
- printf( " %s", mm->axis[i].name );
|
|
915
|
+ printf( "%s", mm->axis[i].name );
|
781
|
916
|
|
782
|
|
- printf( ": [%g;%g], default %g\n",
|
|
917
|
+ printf( ", [%g;%g], default %g\n",
|
783
|
918
|
mm->axis[i].minimum / 65536.0,
|
784
|
919
|
mm->axis[i].maximum / 65536.0,
|
785
|
920
|
mm->axis[i].def / 65536.0 );
|
786
|
921
|
}
|
787
|
922
|
|
|
923
|
+ if ( is_GX )
|
|
924
|
+ {
|
|
925
|
+ FT_Fixed* coords;
|
|
926
|
+ const char* ps_name;
|
|
927
|
+
|
|
928
|
+ FT_Long instance_count;
|
|
929
|
+ FT_UInt default_named_instance;
|
|
930
|
+ FT_Var_Named_Style* named_styles;
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+ /* Show Variation PostScript Name Prefix. */
|
|
934
|
+
|
|
935
|
+ coords = (FT_Fixed*)malloc( mm->num_axis * sizeof ( FT_Fixed ) );
|
|
936
|
+ if ( coords == NULL )
|
|
937
|
+ return;
|
|
938
|
+
|
|
939
|
+ /* We temporarily activate variation font handling. Because we */
|
|
940
|
+ /* use the default axes, the now retrieved PS name is identical */
|
|
941
|
+ /* to the PS name prefix. */
|
|
942
|
+ FT_Get_Var_Design_Coordinates( face, mm->num_axis, coords );
|
|
943
|
+ FT_Set_Var_Design_Coordinates( face, mm->num_axis, coords );
|
|
944
|
+
|
|
945
|
+ ps_name = FT_Get_Postscript_Name( face );
|
|
946
|
+ if ( ps_name == NULL )
|
|
947
|
+ ps_name = "UNAVAILABLE";
|
|
948
|
+
|
|
949
|
+ printf( "\n"
|
|
950
|
+ " VF PS name prefix: %s\n", ps_name );
|
|
951
|
+
|
|
952
|
+ /* Switch off variation font handling. */
|
|
953
|
+ FT_Set_Var_Design_Coordinates( face, 0, NULL );
|
|
954
|
+
|
|
955
|
+ free( coords );
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+ /* Show named instances. */
|
|
959
|
+
|
|
960
|
+ instance_count = face->style_flags >> 16;
|
|
961
|
+ named_styles = mm->namedstyle;
|
|
962
|
+
|
|
963
|
+ FT_Get_Default_Named_Instance( face, &default_named_instance );
|
|
964
|
+ default_named_instance--; /* `named_styles` is a zero-based array */
|
|
965
|
+
|
|
966
|
+ printf( "\n" );
|
|
967
|
+ printf( " named instances (%lu)\n", instance_count );
|
|
968
|
+
|
|
969
|
+ for ( i = 0; i < instance_count; i++ )
|
|
970
|
+ {
|
|
971
|
+ int pos;
|
|
972
|
+ FT_UInt j;
|
|
973
|
+ FT_Bool semicolon;
|
|
974
|
+ FT_Fixed* c;
|
|
975
|
+
|
|
976
|
+
|
|
977
|
+ /* Since FreeType starts the instance numbering with value 1 */
|
|
978
|
+ /* in `face_index` we report the same here for consistency. */
|
|
979
|
+ pos = printf( " %u: ", i + 1);
|
|
980
|
+
|
|
981
|
+ name.string = NULL;
|
|
982
|
+ get_english_name_entry( face, named_styles[i].strid, &name );
|
|
983
|
+ if ( name.string )
|
|
984
|
+ {
|
|
985
|
+ if ( name.platform_id == TT_PLATFORM_MACINTOSH )
|
|
986
|
+ put_ascii( name.string, name.string_len, 0 );
|
|
987
|
+ else
|
|
988
|
+ put_unicode_be16( name.string, name.string_len, 0, utf8 );
|
|
989
|
+ }
|
|
990
|
+ else
|
|
991
|
+ printf( "UNAVAILABLE" );
|
|
992
|
+ printf( "%s\n", i == default_named_instance ? " (default)" : "" );
|
|
993
|
+
|
|
994
|
+ name.string = NULL;
|
|
995
|
+ get_english_name_entry( face, named_styles[i].psid, &name );
|
|
996
|
+ printf( "%*s PS: ", pos, "" );
|
|
997
|
+ if ( name.string )
|
|
998
|
+ {
|
|
999
|
+ if ( name.platform_id == TT_PLATFORM_MACINTOSH )
|
|
1000
|
+ put_ascii( name.string, name.string_len, 0 );
|
|
1001
|
+ else
|
|
1002
|
+ put_unicode_be16( name.string, name.string_len, 0, utf8 );
|
|
1003
|
+ }
|
|
1004
|
+ else
|
|
1005
|
+ printf( "UNAVAILABLE" );
|
|
1006
|
+ printf( "\n" );
|
|
1007
|
+
|
|
1008
|
+ semicolon = 0;
|
|
1009
|
+ c = named_styles[i].coords;
|
|
1010
|
+
|
|
1011
|
+ printf( "%*scoord: (", pos, "" );
|
|
1012
|
+ for ( j = 0; j < mm->num_axis; j++ )
|
|
1013
|
+ {
|
|
1014
|
+ printf( "%s%g", semicolon ? ";" : "", c[j] / 65536.0);
|
|
1015
|
+ semicolon = 1;
|
|
1016
|
+ }
|
|
1017
|
+ printf( ")\n" );
|
|
1018
|
+ }
|
|
1019
|
+
|
|
1020
|
+ printf( "\n" );
|
|
1021
|
+ }
|
|
1022
|
+
|
788
|
1023
|
FT_Done_MM_Var( face->glyph->library, mm );
|
789
|
1024
|
}
|
790
|
1025
|
|
... |
... |
@@ -1350,10 +1585,15 @@ |
1350
|
1585
|
Print_Charmaps( face );
|
1351
|
1586
|
}
|
1352
|
1587
|
|
|
1588
|
+ /* FT_IS_CID_KEYED() does not catch an OpenType/CFF,
|
|
1589
|
+ * let Print_ROS_From_Face() catch various cases.
|
|
1590
|
+ */
|
|
1591
|
+ Print_ROS_From_Face( face );
|
|
1592
|
+
|
1353
|
1593
|
if ( FT_HAS_MULTIPLE_MASTERS( face ) )
|
1354
|
1594
|
{
|
1355
|
1595
|
printf( "\n" );
|
1356
|
|
- Print_MM_Axes( face );
|
|
1596
|
+ Print_MM_Info( face );
|
1357
|
1597
|
}
|
1358
|
1598
|
|
1359
|
1599
|
FT_Done_Face( face );
|