[ftfuzzer] Handle TTCs and MM/GX variations.

This patch also contains various other improvements.

* src/tools/ftfuzzer/ftfuzzer.cc: Add preprocessor guard to reject
pre-C++11 compilers.
(FT_Global): New class.  Use it to provide a global constructor and
destructor for the `FT_Library' object.
(setIntermediateAxis): New function to select an (arbitrary)
instance.
(LLVMFuzzerTestOneInput): Loop over all faces and named instances.
Also call `FT_Set_Char_Size'.
This commit is contained in:
Werner Lemberg 2015-10-13 11:51:13 +02:00
parent 43a96eb26f
commit bdb56bba86
2 changed files with 140 additions and 26 deletions

View File

@ -1,3 +1,18 @@
2015-10-13 Werner Lemberg <wl@gnu.org>
[ftfuzzer] Handle TTCs and MM/GX variations.
This patch also contains various other improvements.
* src/tools/ftfuzzer/ftfuzzer.cc: Add preprocessor guard to reject
pre-C++11 compilers.
(FT_Global): New class. Use it to provide a global constructor and
destructor for the `FT_Library' object.
(setIntermediateAxis): New function to select an (arbitrary)
instance.
(LLVMFuzzerTestOneInput): Loop over all faces and named instances.
Also call `FT_Set_Char_Size'.
2015-10-13 Werner Lemberg <wl@gnu.org>
[truetype] Refine some GX sanity tests.

View File

@ -1,6 +1,18 @@
// we use `unique_ptr' and `decltype', defined since C++11
#if __cplusplus < 201103L
# error "a C++11 compiler is needed"
#endif
#include <assert.h>
#include <stdint.h>
#include <memory>
#include <vector>
using namespace std;
#include <ft2build.h>
#include FT_FREETYPE_H
@ -16,60 +28,147 @@
#include FT_MODULE_H
#include FT_CFF_DRIVER_H
#include FT_TRUETYPE_DRIVER_H
#include FT_MULTIPLE_MASTERS_H
static FT_Library library;
static int InitResult = FT_Init_FreeType( &library );
static int InitResult;
struct FT_Global {
FT_Global() {
InitResult = FT_Init_FreeType( &library );
}
~FT_Global() {
FT_Done_FreeType( library );
}
};
FT_Global global_ft;
static void
setIntermediateAxis( FT_Face face )
{
// only handle Multiple Masters and GX variation fonts
if ( !( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) )
return;
// get variation data for current instance
FT_MM_Var* variations_ptr = nullptr;
if ( FT_Get_MM_Var( face, &variations_ptr ) )
return;
unique_ptr<FT_MM_Var,
decltype ( free )*> variations( variations_ptr, free );
vector<FT_Fixed> coords( variations->num_axis );
// select an arbitrary instance
for ( unsigned int i = 0; i < variations->num_axis; i++ )
coords[i] = ( variations->axis[i].minimum +
variations->axis[i].def ) / 2;
if ( FT_Set_Var_Design_Coordinates( face,
coords.size(),
coords.data() ) )
return;
}
extern "C" int
LLVMFuzzerTestOneInput( const uint8_t* data,
size_t size )
size_t size_ )
{
assert( !InitResult );
if ( size < 1 )
if ( size_ < 1 )
return 0;
long size = (long)size_;
FT_Face face;
FT_Int32 load_flags = FT_LOAD_DEFAULT;
#if 0
FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
#endif
if ( !FT_New_Memory_Face( library, data, size, 0, &face ) )
// We use a conservative approach here, at the cost of calling
// `FT_New_Face' quite often. The idea is that the fuzzer should be
// able to try all faces and named instances of a font, expecting that
// some faces don't work for various reasons, e.g., a broken subfont, or
// an unsupported NFNT bitmap font in a Mac dfont resource that holds
// more than a single font.
// get number of faces
if ( FT_New_Memory_Face( library, data, size, -1, &face ) )
return 0;
long num_faces = face->num_faces;
FT_Done_Face( face );
// loop over all faces
for ( long face_index = 0;
face_index < num_faces;
face_index++ )
{
unsigned int first_index = 0;
// get number of instances
if ( FT_New_Memory_Face( library,
data,
size,
-( face_index + 1 ),
&face ) )
continue;
long num_instances = face->style_flags >> 16;
FT_Done_Face( face );
for ( unsigned i = first_index;
i < (unsigned int)face->num_glyphs;
i++ )
// load face with and without instances
for ( long instance_index = 0;
instance_index < num_instances + 1;
instance_index++ )
{
if ( FT_Load_Glyph( face, i, load_flags ) )
if ( FT_New_Memory_Face( library,
data,
size,
( instance_index << 16 ) + face_index,
&face ) )
continue;
// Rendering is the most expensive and the least interesting part.
//
// if ( FT_Render_Glyph( face->glyph, render_mode) )
// continue;
// FT_GlyphSlot_Embolden( face->glyph );
// set up 20pt at 72dpi as an arbitrary size
FT_Set_Char_Size( face, 20, 20, 72, 72 );
// test MM interface only for a face without a selected instance
if ( instance_index == 0 )
setIntermediateAxis( face );
// loop over all glyphs
for ( unsigned int glyph_index = 0;
glyph_index < (unsigned int)face->num_glyphs;
glyph_index++ )
{
if ( FT_Load_Glyph( face, glyph_index, load_flags ) )
continue;
// Rendering is the most expensive and the least interesting part.
//
// if ( FT_Render_Glyph( face->glyph, render_mode) )
// continue;
// FT_GlyphSlot_Embolden( face->glyph );
#if 0
FT_Glyph glyph;
FT_Glyph glyph;
if ( !FT_Get_Glyph( face->glyph, &glyph ) )
FT_Done_Glyph( glyph );
if ( !FT_Get_Glyph( face->glyph, &glyph ) )
FT_Done_Glyph( glyph );
FT_Outline* outline = &face->glyph->outline;
FT_Matrix rot30 = { 0xDDB4, -0x8000, 0x8000, 0xDDB4 };
FT_Outline* outline = &face->glyph->outline;
FT_Matrix rot30 = { 0xDDB4, -0x8000, 0x8000, 0xDDB4 };
FT_Outline_Transform( outline, &rot30 );
FT_Outline_Transform( outline, &rot30 );
FT_BBox bbox;
FT_Outline_Get_BBox( outline, &bbox );
FT_BBox bbox;
FT_Outline_Get_BBox( outline, &bbox );
#endif
}
}
FT_Done_Face( face );
FT_Done_Face( face );
}
}
return 0;