@@ -741,4 +741,160 @@ fn copy_system_font() {
741741 assert ! ( matching. attributes( ) . find( CFString :: from_static_string( "NSFontSizeAttribute" ) ) . is_none( ) ) ;
742742
743743 assert_eq ! ( small. postscript_name( ) , cgfont. postscript_name( ) ) ;
744+ //assert!(false);
745+ }
746+
747+
748+ fn calc_table_checksum ( table : & [ u8 ] , skipChecksumAdjust : bool ) -> u32 {
749+ let mut sum = std:: num:: Wrapping ( 0 ) ;
750+ let mut i = 0 ;
751+ let mut chunks = table. chunks_exact ( 4 ) ;
752+ for chunk in & mut chunks {
753+ if skipChecksumAdjust && i == 2 {
754+
755+ } else {
756+ let val = ( chunk[ 0 ] as u32 ) << 24 |
757+ ( chunk[ 1 ] as u32 ) << 16 |
758+ ( chunk[ 2 ] as u32 ) << 8 |
759+ ( chunk[ 3 ] as u32 ) << 0 ;
760+ sum += std:: num:: Wrapping ( val)
761+ }
762+ i += 1 ;
763+ }
764+ let mut val: u32 = 0 ;
765+ let mut shift = 24 ;
766+ for byte in chunks. remainder ( ) {
767+ val |= ( * byte as u32 ) << shift;
768+ shift -= 8 ;
769+ }
770+ sum += std:: num:: Wrapping ( val) ;
771+ sum. 0
772+ }
773+
774+ fn maxPow2LessThanEqual ( a : i32 ) -> i32 {
775+ let x = 1 ;
776+ let mut shift = 0 ;
777+ while ( ( x << ( shift + 1 ) ) <= a) {
778+ shift+=1 ;
779+ }
780+ return shift;
781+ }
782+
783+
784+ fn construct_font_data ( font : CGFont ) -> Vec < u8 > {
785+ struct TableRecord {
786+ tag : u32 ,
787+ checkSum : u32 ,
788+ offset : u32 ,
789+ length : u32 ,
790+ data : CFData ,
791+ }
792+
793+ let tags = font. copy_table_tags ( ) ;
794+ let count = tags. len ( ) ;
795+ let mut records = Vec :: with_capacity ( tags. len ( ) as usize ) ;
796+ let mut offset: u32 = 0 ;
797+ offset += std:: mem:: size_of :: < u32 > ( ) as u32 * 3 ;
798+ offset += std:: mem:: size_of :: < u32 > ( ) as u32 * 4 * count as u32 ;
799+ let mut CFF = false ;
800+ for tag in tags. iter ( ) {
801+ let data = font. copy_table_for_tag ( * tag) . unwrap ( ) ;
802+ let skipChecksumAdjust = * tag == 0x68656164 ; // 'head'
803+
804+ if * tag == 0x43464620 { // 'CFF '
805+ CFF = true ;
806+ }
807+ let checkSum = calc_table_checksum ( data. bytes ( ) , skipChecksumAdjust) ;
808+ records. push ( TableRecord { tag : * tag, offset, length : data. len ( ) as u32 , data : data. clone ( ) , checkSum} ) ;
809+ offset += data. len ( ) as u32 ;
810+ // 32 bit align the tables
811+ offset = ( offset + 3 ) & !3 ;
812+ }
813+
814+ let mut buf: Vec < u8 > = Vec :: new ( ) ;
815+ if CFF {
816+ buf. extend_from_slice ( & 0x4f54544fu32 . to_be_bytes ( ) ) ;
817+ } else {
818+ buf. extend_from_slice ( & 0x00010000u32 . to_be_bytes ( ) ) ;
819+ }
820+
821+ buf. extend_from_slice ( & ( count as u16 ) . to_be_bytes ( ) ) ;
822+ let maxPow2Count = maxPow2LessThanEqual ( count as i32 ) ;
823+ buf. extend_from_slice ( & ( ( 1u16 << maxPow2Count) * 16 ) . to_be_bytes ( ) ) ;
824+ buf. extend_from_slice ( & ( maxPow2Count as u16 ) . to_be_bytes ( ) ) ;
825+ buf. extend_from_slice ( & ( ( count as u16 - ( 1 << maxPow2Count) ) * 16 ) . to_be_bytes ( ) ) ;
826+
827+ // write table record entries
828+ for rec in & records {
829+ buf. extend_from_slice ( & rec. tag . to_be_bytes ( ) ) ;
830+ buf. extend_from_slice ( & rec. checkSum . to_be_bytes ( ) ) ;
831+ buf. extend_from_slice ( & rec. offset . to_be_bytes ( ) ) ;
832+ buf. extend_from_slice ( & rec. length . to_be_bytes ( ) ) ;
833+ }
834+
835+ // write tables
836+ let mut checksum_adjustment_offset = 0 ;
837+ for rec in & records {
838+ if rec. tag == 0x68656164 { // 'head'
839+ checksum_adjustment_offset = buf. len ( ) + 2 * 4 ;
840+ }
841+ assert ! ( buf. len( ) == rec. offset as usize ) ;
842+ buf. extend_from_slice ( rec. data . bytes ( ) ) ;
843+ // align
844+ let extra = ( ( buf. len ( ) + 3 ) & !3 ) - buf. len ( ) ;
845+ buf. extend_from_slice ( & [ 0 ; 4 ] [ 0 ..extra] ) ;
846+ }
847+
848+ // clear the checksumAdjust field before checksumming the whole font
849+ for b in & mut buf[ checksum_adjustment_offset..checksum_adjustment_offset+4 ] {
850+ * b = 0 ;
851+ }
852+ let font_check_sum = ( 0xb1b0afbau32 . wrapping_sub (
853+ calc_table_checksum ( & buf, false ) ) ) . to_be_bytes ( ) ;
854+ ( & mut buf[ checksum_adjustment_offset..checksum_adjustment_offset+4 ] ) . copy_from_slice ( & font_check_sum) ;
855+
856+ buf
857+ }
858+
859+ #[ test]
860+ fn font_data ( ) {
861+ let small = new_from_name ( "Zapf Dingbats" , 19. ) . unwrap ( ) ;
862+ let small = unsafe {
863+ CTFont :: wrap_under_create_rule (
864+ CTFontCreateUIFontForLanguage ( kCTFontSystemDetailFontType, 19. , std:: ptr:: null ( ) )
865+ )
866+ } ;
867+ println ! ( "{:?}" , ( small. postscript_name( ) , small. url( ) ) ) ;
868+ let data = construct_font_data ( small. copy_to_CGFont ( ) ) ;
869+ let mut file = std:: fs:: File :: create ( "test.ttf" ) . unwrap ( ) ;
870+ // Write a slice of bytes to the file
871+ use std:: io:: Write ;
872+ file. write_all ( & data) ;
873+ drop ( file) ;
874+ let font = new_from_buffer ( & data) . unwrap ( ) ;
875+ println ! ( "{:?}" , ( font. postscript_name( ) , font. url( ) ) ) ;
876+ //assert!(false);
877+ }
878+
879+ #[ test]
880+ fn variations ( ) {
881+ let mut vals_str: Vec < ( CFString , CFNumber ) > = Vec :: new ( ) ;
882+ let small = unsafe {
883+ CTFont :: wrap_under_create_rule (
884+ CTFontCreateUIFontForLanguage ( kCTFontEmphasizedSystemDetailFontType, 19. , std:: ptr:: null ( ) )
885+ )
886+ } ;
887+ dbg ! ( & small) ;
888+ //let font = CGFont::from_name(&CFString::new(".SFNSText-Bold")).unwrap();
889+ let font= small. copy_to_CGFont ( ) ;
890+ vals_str. push ( ( CFString :: new ( "Weight" ) , ( 700. ) . into ( ) ) ) ;
891+ let vars = CFDictionary :: from_CFType_pairs ( & vals_str) ;
892+ let var_font = CGFont :: create_copy_from_variations ( & font, & vars) . unwrap ( ) ;
893+ extern {
894+ pub fn CFCopyDescription ( obj : usize ) -> usize ;
895+ }
896+ let s: CFString = unsafe { std:: mem:: transmute ( CFCopyDescription ( std:: mem:: transmute ( var_font. clone ( ) ) ) ) } ;
897+ println ! ( "{:}" , s) ;
898+ dbg ! ( new_from_CGFont( & var_font. clone( ) , 19. ) ) ;
899+ assert ! ( false ) ;
744900}
0 commit comments