@@ -40,6 +40,9 @@ export interface WASMInstance {
4040 ) => number
4141 save_subset_to_file : ( subset_handle : number , path_ptr : number , path_len : number ) => number
4242
43+ convert_ttf_to_woff : ( font_ptr : number , font_len : number , output_ptr : number , output_len : number ) => number
44+ convert_ttf_to_woff_from_reader : ( reader_handle : number , output_ptr : number , output_len : number ) => number
45+
4346 get_error_message_length : ( error_code : number ) => number
4447 get_error_message : ( error_code : number , buffer_ptr : number , buffer_len : number ) => number
4548}
@@ -48,6 +51,7 @@ export interface WASMZigEnv extends WebAssembly.ModuleImports {
4851 host_read_file : ( pathPtr : number , pathLen : number , outPtrPtr : number , outLenPtr : number ) => boolean
4952 host_write_file : ( pathPtr : number , pathLen : number , dataPtr : number , dataLen : number ) => boolean
5053 host_head_modified_time : ( outTimestampPtr : number ) => boolean
54+ host_compress_data : ( inputPtr : number , inputLen : number , outputPtrPtr : number , outputLenPtr : number ) => boolean
5155}
5256
5357const MAC_EPOCH_OFFSET = 2082844800 // Offset from Unix epoch to Mac epoch
@@ -59,7 +63,8 @@ export const ERR_CODE = {
5963 PARSE_FAILED : 3 ,
6064 INVALID_UTF8 : 4 ,
6165 MISSING_TABLE : 5 ,
62- OUT_OF_BOUNDS : 6
66+ OUT_OF_BOUNDS : 6 ,
67+ COMPRESSION_FAILED : 7
6368} as const
6469
6570export interface FontMetrics {
@@ -87,9 +92,13 @@ const IS_NODE_PLATFORM = typeof process !== 'undefined' && process.versions?.nod
8792let FS_WRAP : Promise < typeof import ( 'fs' ) > | null = null
8893let fs : typeof import ( 'fs' ) | null = null
8994
95+ let ZLIB_WRAP : Promise < typeof import ( 'zlib' ) > | null = null
96+ let zlib : typeof import ( 'zlib' ) | null = null
97+
9098if ( IS_NODE_PLATFORM ) {
9199 try {
92100 FS_WRAP = import ( 'fs' ) . then ( ( fsModule ) => fsModule . default || fsModule )
101+ ZLIB_WRAP = import ( 'zlib' ) . then ( ( zlibModule ) => zlibModule . default || zlibModule )
93102 } catch {
94103 }
95104}
@@ -107,6 +116,51 @@ export class FontSubset {
107116 this . instance = instance
108117 }
109118
119+ static async convertTtfToWoff ( instance : WASMInstance , fontData : Uint8Array ) {
120+ if ( ! zlib && IS_NODE_PLATFORM && ZLIB_WRAP ) {
121+ zlib = await ZLIB_WRAP
122+ }
123+ const fontPtr = instance . allocate_memory ( fontData . length )
124+ if ( fontPtr === null ) { return null }
125+
126+ const outputPtrPtr = instance . allocate_memory ( 4 )
127+ const outputLenPtr = instance . allocate_memory ( 4 )
128+
129+ if ( outputPtrPtr === null || outputLenPtr === null ) {
130+ instance . free_memory ( fontPtr , fontData . length )
131+ if ( outputPtrPtr ) { instance . free_memory ( outputPtrPtr , 4 ) }
132+ if ( outputLenPtr ) { instance . free_memory ( outputLenPtr , 4 ) }
133+ return null
134+ }
135+
136+ try {
137+ const memory = new Uint8Array ( instance . memory . buffer )
138+ memory . set ( fontData , fontPtr )
139+
140+ const errorCode = instance . convert_ttf_to_woff ( fontPtr , fontData . length , outputPtrPtr , outputLenPtr )
141+
142+ if ( errorCode !== ERR_CODE . SUCCESS ) {
143+ return null
144+ }
145+
146+ const outputPtr = new Uint32Array ( instance . memory . buffer , outputPtrPtr , 1 ) [ 0 ]
147+ const outputLen = new Uint32Array ( instance . memory . buffer , outputLenPtr , 1 ) [ 0 ]
148+
149+ if ( outputLen === 0 ) { return new Uint8Array ( 0 ) }
150+
151+ const result = new Uint8Array ( instance . memory . buffer , outputPtr , outputLen )
152+ const copy = new Uint8Array ( result )
153+
154+ instance . free_memory ( outputPtr , outputLen )
155+
156+ return copy
157+ } finally {
158+ instance . free_memory ( fontPtr , fontData . length )
159+ instance . free_memory ( outputPtrPtr , 4 )
160+ instance . free_memory ( outputLenPtr , 4 )
161+ }
162+ }
163+
110164 static createSubsetFromText ( instance : WASMInstance , fontData : Uint8Array , text : string ) : Uint8Array | null {
111165 const fontPtr = instance . allocate_memory ( fontData . length )
112166 if ( fontPtr === null ) { return null }
@@ -504,6 +558,34 @@ export function createSubsetEngine(binary: Uint8Array): FontSubset {
504558 } catch {
505559 return false
506560 }
561+ } ,
562+ host_compress_data ( inputPtr , inputLen , outputPtrPtr , outputLenPtr ) {
563+ try {
564+ if ( ! WASM_INSTANCE ) { return false }
565+ if ( IS_NODE_PLATFORM && zlib ) {
566+ const memory = new Uint8Array ( WASM_INSTANCE . memory . buffer )
567+ const inputData = memory . slice ( inputPtr , inputPtr + inputLen )
568+
569+ const compressedData = zlib . deflateSync ( inputData )
570+
571+ const outputPtr = WASM_INSTANCE . allocate_memory ( compressedData . length )
572+ if ( outputPtr === null ) { return false }
573+
574+ const outputMemory = new Uint8Array ( WASM_INSTANCE . memory . buffer )
575+ outputMemory . set ( compressedData , outputPtr )
576+
577+ const outPtrView = new Uint32Array ( WASM_INSTANCE . memory . buffer , outputPtrPtr , 1 )
578+ const outLenView = new Uint32Array ( WASM_INSTANCE . memory . buffer , outputLenPtr , 1 )
579+
580+ outPtrView [ 0 ] = outputPtr
581+ outLenView [ 0 ] = compressedData . length
582+
583+ return true
584+ }
585+ return false
586+ } catch {
587+ return false
588+ }
507589 }
508590 }
509591 WASM_INSTANCE = new WebAssembly . Instance ( compiledWASM , { env } ) . exports as unknown as WASMInstance
@@ -518,3 +600,8 @@ export function createSubsetFromText(
518600 if ( ! WASM_INSTANCE ) { return null }
519601 return FontSubset . createSubsetFromText ( WASM_INSTANCE , fontData , text )
520602}
603+
604+ export async function convertTtfToWoff ( fontData : Uint8Array ) {
605+ if ( ! WASM_INSTANCE ) { return null }
606+ return FontSubset . convertTtfToWoff ( WASM_INSTANCE , fontData )
607+ }
0 commit comments