ref: 106bacf5022e8c7c8bdcd8407efd64fb6db182b4
parent: 18f6ff11f91e377d6296bad2ece8bb2be7dbb0e2
author: Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
date: Thu Jul 4 21:09:52 EDT 2019
[woff2] Create stream for uncompressed buffer. Uncompressed buffer is now an `FT_Stream'. Perform basic checks and start iterating over tables. * src/sfnt/sfwoff2.c (stream_close, find_table, read_num_hmetrics): New functions. (reconstruct_font): Modify parameters and iterate over tables. (woff2_open_font): Updated.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2019-08-27 Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
+ [woff2] Create stream for uncompressed buffer.
+
+ Uncompressed buffer is now an `FT_Stream'.
+
+ Perform basic checks and start iterating over tables.
+
+ * src/sfnt/sfwoff2.c (stream_close, find_table, read_num_hmetrics):
+ New functions.
+ (reconstruct_font): Modify parameters and iterate over tables.
+ (woff2_open_font): Updated.
+
+2019-08-27 Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
+
[woff2] Handle TTCs and start reconstructing font.
We `handle' TTCs by modifying the `indices' array to point to only
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -65,6 +65,20 @@
} while ( 0 )
+ static void
+ stream_close( FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( stream->base );
+
+ stream->size = 0;
+ stream->base = NULL;
+ stream->close = NULL;
+ }
+
+
FT_CALLBACK_DEF( int )
compare_tags( const void* a,
const void* b )
@@ -235,23 +249,140 @@
}
+ static WOFF2_Table
+ find_table( WOFF2_Table* tables,
+ FT_UShort num_tables,
+ FT_ULong tag )
+ {
+ FT_Int i;
+
+ for ( i = 0; i < num_tables; i++ )
+ {
+ if( tables[i]->Tag == tag )
+ return tables[i];
+ }
+ return NULL;
+ }
+
+
+ /* Read `numberOfHMetrics' from `hhea' table. */
static FT_Error
+ read_num_hmetrics( FT_Stream stream,
+ FT_ULong table_len,
+ FT_UShort* num_hmetrics )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_UShort num_metrics;
+
+ if( FT_STREAM_SKIP( 34 ) )
+ return FT_THROW( Invalid_Table );
+
+ if( FT_READ_USHORT( num_metrics ) )
+ return FT_THROW( Invalid_Table );
+
+ *num_hmetrics = num_metrics;
+
+ FT_TRACE2(( "num_hmetrics = %d\n", *num_hmetrics ));
+
+ return error;
+ }
+
+
+ static FT_Error
reconstruct_font( FT_Byte* transformed_buf,
FT_ULong transformed_buf_size,
WOFF2_Table* indices,
WOFF2_Header woff2,
- FT_Int face_index,
- FT_Byte* sfnt )
+ FT_Byte* sfnt,
+ FT_Memory memory )
{
- /* We're writing only one face per call, so offset is fixed. */
- FT_ULong dst_offset = 12;
- FT_Byte* table_entry = NULL;
+ FT_Error error = FT_Err_Ok;
+ FT_Stream stream = NULL;
+ /* We're writing only one face per call, so initial offset is fixed. */
+ FT_ULong dst_offset = 12;
+ FT_UShort num_tables = woff2->num_tables;
+
+ FT_ULong checksum = 0;
+ FT_ULong loca_checksum = 0;
+ FT_Int nn = 0;
+ FT_UShort num_hmetrics;
+
+ /* Few table checks before reconstruction. */
+ /* `glyf' must be present with `loca'. */
+ const WOFF2_Table glyf_table = find_table( indices, num_tables,
+ TTAG_glyf );
+ const WOFF2_Table loca_table = find_table( indices, num_tables,
+ TTAG_loca );
+
+ if( ( !glyf_table && loca_table ) ||
+ ( !loca_table && glyf_table ) )
+ {
+ FT_ERROR(( "Cannot have only one of glyf/loca.\n" ));
+ return FT_THROW( Invalid_Table );
+ }
+
+ /* Both `glyf' and `loca' must have same transformation. */
+ if( glyf_table != NULL )
+ {
+ if( ( glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) !=
+ ( loca_table->flags & WOFF2_FLAGS_TRANSFORM ) )
+ {
+ FT_ERROR(( "Transformation mismatch in glyf and loca." ));
+ return FT_THROW( Invalid_Table );
+ }
+ }
+
FT_UNUSED( dst_offset );
- FT_UNUSED( table_entry );
+ FT_UNUSED( loca_checksum );
+ FT_UNUSED( checksum );
- /* TODO reconstruct the font tables! */
+ /* Create a stream for the uncompressed buffer. */
+ if ( FT_NEW( stream ) )
+ return FT_THROW( Invalid_Table );
+ FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size );
+ stream->close = stream_close;
+ FT_ASSERT( FT_STREAM_POS() == 0 );
+
+ /* Reconstruct/copy tables to output stream. */
+ for ( nn = 0; nn < num_tables; nn++ )
+ {
+ WOFF2_TableRec table = *( indices[nn] );
+
+ /* DEBUG - Remove later */
+ FT_TRACE2(( "Seeking to %d with table size %d.\n", table.src_offset, table.src_length ));
+ FT_TRACE2(( "Table tag: %c%c%c%c.\n",
+ (FT_Char)( table.Tag >> 24 ),
+ (FT_Char)( table.Tag >> 16 ),
+ (FT_Char)( table.Tag >> 8 ),
+ (FT_Char)( table.Tag ) ));
+ if ( FT_STREAM_SEEK( table.src_offset ) )
+ return FT_THROW( Invalid_Table );
+
+ if( table.src_offset + table.src_length > transformed_buf_size )
+ return FT_THROW( Invalid_Table );
+
+ /* Get stream size for fields of `hmtx' table. */
+ if( table.Tag == TTAG_hhea )
+ {
+ if( read_num_hmetrics( stream, table.src_length, &num_hmetrics ) )
+ return FT_THROW( Invalid_Table );
+ }
+
+ if( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM )
+ {
+ /* Check if `head' is atleast 12 bytes. */
+ if( table.Tag == TTAG_head )
+ {
+ if( table.src_length < 12 )
+ return FT_THROW( Invalid_Table );
+ }
+ }
+
+ }
+
+ /* TODO reconstruct the font tables! */
return FT_Err_Ok;
}
@@ -564,6 +695,8 @@
ttc_font->num_tables ) )
goto Exit;
+ /* DEBUG - Remove later */
+ FT_TRACE2(( "Storing tables for TTC face index %d.\n", face_index ));
for ( nn = 0; nn < ttc_font->num_tables; nn++ )
{
/* DEBUG - Remove later */
@@ -660,7 +793,7 @@
/* TODO Write table entries. */
reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
- indices, &woff2, face_index, sfnt );
+ indices, &woff2, sfnt, memory );
error = FT_THROW( Unimplemented_Feature );
/* DEBUG - Remove later */