Skip to content

Commit a4b8064

Browse files
committed
Stff
1 parent 39956a4 commit a4b8064

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

core-text/src/font.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)