// rasterfuzzer.cc
//
//   A fuzzing function to test FreeType's rasterizers with libFuzzer.
//
// Copyright 2016 by
// David Turner, Robert Wilhelm, and Werner Lemberg.
//
// This file is part of the FreeType project, and may only be used,
// modified, and distributed under the terms of the FreeType project
// license, LICENSE.TXT.  By continuing to use, modify, or distribute
// this file you indicate that you have read the license and
// understand and accept it fully.


#include <stdint.h>

#include <vector>


  using namespace std;


#include <ft2build.h>

#include FT_FREETYPE_H
#include FT_IMAGE_H
#include FT_OUTLINE_H


  static FT_Library  library;
  static int         InitResult;


  struct FT_Global {
    FT_Global() {
      InitResult = FT_Init_FreeType( &library );
    }
    ~FT_Global() {
      FT_Done_FreeType( library );
    }
  };

  FT_Global  global_ft;


  extern "C" int
  LLVMFuzzerTestOneInput( const uint8_t*  data,
                          size_t          size_ )
  {
    unsigned char  pixels[4];

    FT_Bitmap  bitmap_mono = {
      1,                  // rows
      1,                  // width
      4,                  // pitch
      pixels,             // buffer
      2,                  // num_grays
      FT_PIXEL_MODE_MONO, // pixel_mode
      0,                  // palette_mode
      NULL                // palette
    };

    FT_Bitmap  bitmap_gray = {
      1,                  // rows
      1,                  // width
      4,                  // pitch
      pixels,             // buffer
      256,                // num_grays
      FT_PIXEL_MODE_GRAY, // pixel_mode
      0,                  // palette_mode
      NULL                // palette
    };

    const size_t vsize = sizeof ( FT_Vector );
    const size_t tsize = sizeof ( char );

    // we use the input data for both points and tags
    short  n_points = short( size_ / ( vsize + tsize ) );
    if ( n_points <= 2 )
      return 0;

    FT_Vector*  points = reinterpret_cast<FT_Vector*>(
                           const_cast<uint8_t*>(
                             data ) );
    char*       tags   = reinterpret_cast<char*>(
                           const_cast<uint8_t*>(
                             data + size_t( n_points ) * vsize ) );

    // to reduce the number of invalid outlines that are immediately
    // rejected in `FT_Outline_Render', limit values to 2^18 pixels
    // (i.e., 2^24 bits)
    for ( short  i = 0; i < n_points; i++ )
    {
      if ( points[i].x == LONG_MIN )
        points[i].x = 0;
      else if ( points[i].x < 0 )
        points[i].x = -( -points[i].x & 0xFFFFFF ) - 1;
      else
        points[i].x = ( points[i].x & 0xFFFFFF ) + 1;

      if ( points[i].y == LONG_MIN )
        points[i].y = 0;
      else if ( points[i].y < 0 )
        points[i].y = -( -points[i].y & 0xFFFFFF ) - 1;
      else
        points[i].y = ( points[i].y & 0xFFFFFF ) + 1;
    }

    short  contours[1];
    contours[0] = n_points - 1;

    FT_Outline  outline =
    {
      1,               // n_contours
      n_points,        // n_points
      points,          // points
      tags,            // tags
      contours,        // contours
      FT_OUTLINE_NONE  // flags
    };

    FT_Outline_Get_Bitmap( library, &outline, &bitmap_mono );
    FT_Outline_Get_Bitmap( library, &outline, &bitmap_gray );

    return 0;
  }


// END
