[woff2] Uncompress Brotli streams and `face_index' support.
WOFF2 compressed stream is now uncompressed if Brotli is available. This data is stored in a separate buffer (uncompressed_buf) because it does not contain direct table data. Certain tables have transformations applied to them, and they must be reconstructed before we can write those tables to the SFNT stream. `face_index' is now being passed as a parameter to `woff2_open_font'. * src/sfnt/sfobjs.c (sfnt_open_font): Add parameter `face_instance_index'. * src/sfnt/sfwoff2.c (woff2_uncompress): New function. (woff2_open_font): Call `woff2_uncompress'. (compute_first_table_offset): Fix return type. * src/sfnt/sfwoff2.h (woff2_open_font): Modify declaration.
This commit is contained in:
parent
732da8a4b7
commit
fc65d45a62
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
|||
2019-08-27 Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
|
||||
|
||||
[woff2] Uncompress Brotli streams and `face_index' support.
|
||||
|
||||
WOFF2 compressed stream is now uncompressed if Brotli is available.
|
||||
This data is stored in a separate buffer (uncompressed_buf) because
|
||||
it does not contain direct table data. Certain tables have
|
||||
transformations applied to them, and they must be reconstructed
|
||||
before we can write those tables to the SFNT stream.
|
||||
|
||||
`face_index' is now being passed as a parameter to
|
||||
`woff2_open_font'.
|
||||
|
||||
* src/sfnt/sfobjs.c (sfnt_open_font): Add parameter
|
||||
`face_instance_index'.
|
||||
|
||||
* src/sfnt/sfwoff2.c (woff2_uncompress): New function.
|
||||
(woff2_open_font): Call `woff2_uncompress'.
|
||||
(compute_first_table_offset): Fix return type.
|
||||
|
||||
* src/sfnt/sfwoff2.h (woff2_open_font): Modify declaration.
|
||||
|
||||
2019-08-27 Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
|
||||
|
||||
* builds/unix/configure.raw: Change argument name to `brotli'.
|
||||
|
|
|
@ -342,7 +342,8 @@
|
|||
/* synthesized into a TTC with one offset table. */
|
||||
static FT_Error
|
||||
sfnt_open_font( FT_Stream stream,
|
||||
TT_Face face )
|
||||
TT_Face face,
|
||||
FT_Int face_instance_index )
|
||||
{
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Error error;
|
||||
|
@ -393,7 +394,7 @@
|
|||
if ( FT_STREAM_SEEK( offset ) )
|
||||
return error;
|
||||
|
||||
error = woff2_open_font( stream, face );
|
||||
error = woff2_open_font( stream, face, face_instance_index );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
|
@ -531,7 +532,7 @@
|
|||
|
||||
FT_TRACE2(( "SFNT driver\n" ));
|
||||
|
||||
error = sfnt_open_font( stream, face );
|
||||
error = sfnt_open_font( stream, face, face_instance_index );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
#include FT_INTERNAL_STREAM_H
|
||||
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_USE_BROTLI
|
||||
|
||||
#include <brotli/decode.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* The macro FT_COMPONENT is used in trace mode. It is an implicit
|
||||
|
@ -96,7 +103,7 @@
|
|||
return FT_THROW( Invalid_Table );
|
||||
if( code == wordCode )
|
||||
{
|
||||
/* Read next two bytes and store UInt16 value */
|
||||
/* Read next two bytes and store FT_UShort value */
|
||||
if( FT_READ_USHORT( result_short ) )
|
||||
return FT_THROW( Invalid_Table );
|
||||
*value = result_short;
|
||||
|
@ -176,7 +183,7 @@
|
|||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
static FT_UInt64
|
||||
compute_first_table_offset( const WOFF2_Header woff2 )
|
||||
{
|
||||
FT_Int nn;
|
||||
|
@ -196,12 +203,42 @@
|
|||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
woff2_uncompress( FT_Byte* dst,
|
||||
FT_ULong dst_size,
|
||||
const FT_Byte* src,
|
||||
FT_ULong src_size )
|
||||
{
|
||||
#ifdef FT_CONFIG_OPTION_USE_BROTLI
|
||||
|
||||
FT_ULong uncompressed_size = dst_size;
|
||||
BrotliDecoderResult result;
|
||||
|
||||
result = BrotliDecoderDecompress(
|
||||
src_size, src, &uncompressed_size, dst);
|
||||
|
||||
if( result != BROTLI_DECODER_RESULT_SUCCESS ||
|
||||
uncompressed_size != dst_size )
|
||||
return FT_THROW( Invalid_Table );
|
||||
|
||||
return FT_Err_Ok;
|
||||
|
||||
#else /* !FT_CONFIG_OPTION_USE_BROTLI */
|
||||
|
||||
FT_ERROR(( "woff2_uncompress: Brotli support not available.\n" ));
|
||||
return FT_THROW( Unimplemented_Feature );
|
||||
|
||||
#endif /* !FT_CONFIG_OPTION_USE_BROTLI */
|
||||
}
|
||||
|
||||
|
||||
/* Replace `face->root.stream' with a stream containing the extracted */
|
||||
/* SFNT of a WOFF2 font. */
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
woff2_open_font( FT_Stream stream,
|
||||
TT_Face face )
|
||||
TT_Face face,
|
||||
FT_Int face_index )
|
||||
{
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
@ -227,6 +264,8 @@
|
|||
FT_Stream sfnt_stream = NULL;
|
||||
FT_Byte* sfnt_header;
|
||||
|
||||
FT_Byte* uncompressed_buf = NULL;
|
||||
|
||||
static const FT_Frame_Field woff2_header_fields[] =
|
||||
{
|
||||
#undef FT_STRUCTURE
|
||||
|
@ -256,7 +295,7 @@
|
|||
FT_ASSERT( FT_STREAM_POS() == 0 );
|
||||
|
||||
/* DEBUG - Remove later. */
|
||||
FT_TRACE2(( "Face index = %ld\n", face->root.face_index ));
|
||||
FT_TRACE2(( "Face index = %ld\n", face_index ));
|
||||
|
||||
/* Read WOFF2 Header. */
|
||||
if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) )
|
||||
|
@ -306,7 +345,6 @@
|
|||
" tag flags transform origLen transformLen\n"
|
||||
" --------------------------------------------------\n" ));
|
||||
|
||||
/* TODO check whether there is sufficient input before FT_READ_*. */
|
||||
for ( nn = 0; nn < woff2.num_tables; nn++ )
|
||||
{
|
||||
WOFF2_Table table = tables + nn;
|
||||
|
@ -455,7 +493,7 @@
|
|||
return FT_THROW( Invalid_Table );
|
||||
/* DEBUG - Remove later */
|
||||
else
|
||||
FT_TRACE2(( "glyf and loca are valid.\n" ));
|
||||
FT_TRACE2(( "glyf and loca indices are valid.\n" ));
|
||||
}
|
||||
}
|
||||
/* Collection directory reading complete. */
|
||||
|
@ -470,7 +508,7 @@
|
|||
file_offset = ROUND4( woff2.compressed_offset +
|
||||
woff2.totalCompressedSize );
|
||||
|
||||
/* Few more checks before we start reading the tables */
|
||||
/* Few more checks before we start reading the tables. */
|
||||
if( file_offset > woff2.length )
|
||||
return FT_THROW( Invalid_Table );
|
||||
|
||||
|
@ -491,6 +529,7 @@
|
|||
if( file_offset != ( ROUND4( woff2.length ) ) )
|
||||
return FT_THROW( Invalid_Table );
|
||||
|
||||
/* TODO Add support for uncompression of TTC fonts. */
|
||||
/* Redirect a TTC to exit for now. */
|
||||
if( woff2.header_version )
|
||||
{
|
||||
|
@ -551,6 +590,27 @@
|
|||
(FT_Char)( table->Tag )));
|
||||
}
|
||||
|
||||
if( woff2.uncompressed_size < 1 )
|
||||
{
|
||||
error = FT_THROW( Invalid_Table );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* Allocate memory for uncompressed table data. */
|
||||
if ( FT_ALLOC( uncompressed_buf, woff2.uncompressed_size ) ||
|
||||
FT_FRAME_ENTER( woff2.totalCompressedSize ) )
|
||||
goto Exit;
|
||||
|
||||
/* Uncompress the stream. */
|
||||
error = woff2_uncompress( uncompressed_buf, woff2.uncompressed_size,
|
||||
stream->cursor, woff2.totalCompressedSize );
|
||||
if( error )
|
||||
goto Exit;
|
||||
|
||||
FT_FRAME_EXIT();
|
||||
|
||||
/* TODO Write table entries. */
|
||||
|
||||
error = FT_THROW( Unimplemented_Feature );
|
||||
/* DEBUG - Remove later */
|
||||
FT_TRACE2(( "Reached end without errors.\n" ));
|
||||
|
|
|
@ -30,7 +30,8 @@ FT_BEGIN_HEADER
|
|||
|
||||
FT_LOCAL( FT_Error )
|
||||
woff2_open_font( FT_Stream stream,
|
||||
TT_Face face );
|
||||
TT_Face face,
|
||||
FT_Int face_index );
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
|
Loading…
Reference in New Issue