freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] gsoc-anurag-2022 63dd92439 03/27: Added things


From: Werner Lemberg
Subject: [freetype2] gsoc-anurag-2022 63dd92439 03/27: Added things
Date: Mon, 3 Oct 2022 17:51:48 -0400 (EDT)

branch: gsoc-anurag-2022
commit 63dd924394ebc4b72f8c780a97de68a24aed795c
Author: Anurag Thakur <anurag105csec21@bpitindia.edu.in>
Commit: Anurag Thakur <anurag105csec21@bpitindia.edu.in>

    Added things
---
 .vscode/settings.json   |   3 +-
 src/dense/ftdense.c     | 619 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/dense/ftdense.h     | 142 +++++++++++
 src/dense/ftdenserend.c | 357 ++++++++++++++++++++++++++++
 src/dense/ftdenserend.h |  73 ++++++
 5 files changed, 1193 insertions(+), 1 deletion(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index f273162bf..652233883 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,6 @@
 {
     "files.associations": {
-        "ftoutln.h": "c"
+        "ftoutln.h": "c",
+        "svprop.h": "c"
     }
 }
\ No newline at end of file
diff --git a/src/dense/ftdense.c b/src/dense/ftdense.c
index fd09b747c..4f83c934e 100644
--- a/src/dense/ftdense.c
+++ b/src/dense/ftdense.c
@@ -1,3 +1,622 @@
 /** The rasterizer for the 'dense' renderer */
 
+#undef FT_COMPONENT
+#define FT_COMPONENT dense
+
+#include <freetype/ftoutln.h>
+#include <freetype/internal/ftcalc.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftobjs.h>
+#include "ftdense.h"
+
+#include "ftdenseerrs.h"
+
+typedef struct dense_TRaster_
+{
+  void* memory;
+
+} dense_TRaster, *dense_PRaster;
+
+static RasterFP_Point
+Lerp( float aT, RasterFP_Point aP0, RasterFP_Point aP1 )
+{
+  RasterFP_Point p;
+  p.m_x = aP0.m_x + aT * ( aP1.m_x - aP0.m_x );
+  p.m_y = aP0.m_y + aT * ( aP1.m_y - aP0.m_y );
+  return p;
+}
+
+static int
+dense_move_to( const FT_Vector* to, RasterFP* aRasterFP )
+{
+
+  RasterFP_Point lp = {to->x, to->y};
+
+  aRasterFP->last_point = lp;
+  return 0;
+}
+
+static int
+dense_line_to( const FT_Vector* to, RasterFP* aRasterFP )
+{
+  RasterFP_Point tp = {to->x, to->y};
+  RasterFP_DrawLine(aRasterFP, aRasterFP->last_point, tp);
+  return 0;
+}
+
+void
+RasterFP_DrawLine( RasterFP* aRasterFP, RasterFP_Point aP0, RasterFP_Point aP1 
)
+{
+  assert( aRasterFP );
+  if ( aP0.m_y == aP1.m_y )
+    return;
+
+  aP0.m_x -= aRasterFP->m_origin_x;
+  aP0.m_y -= aRasterFP->m_origin_y;
+  aP1.m_x -= aRasterFP->m_origin_x;
+  aP1.m_y -= aRasterFP->m_origin_y;
+
+  float dir;
+  if ( aP0.m_y < aP1.m_y )
+    dir = 1;
+  else
+  {
+    dir                 = -1;
+    RasterFP_Point temp = aP0;
+    aP0                 = aP1;
+    aP1                 = temp;
+  }
+
+  // Clip to the height.
+  if ( aP0.m_y >= aRasterFP->m_h || aP1.m_y <= 0 )
+    return;
+
+  float dxdy = ( aP1.m_x - aP0.m_x ) / ( aP1.m_y - aP0.m_y );
+  if ( aP0.m_y < 0 )
+  {
+    aP0.m_x -= aP0.m_y * dxdy;
+    aP0.m_y = 0;
+  }
+  if ( aP1.m_y > aRasterFP->m_h )
+  {
+    aP1.m_x -= ( aP1.m_y - aRasterFP->m_h ) * dxdy;
+    aP1.m_y = (float)aRasterFP->m_h;
+  }
+
+  /**
+  Handle parts of the line outside the clip rectangle by
+  snapping them to the left or right edge, or, if they intersect the clip area,
+  by recursive calls.
+  */
+  RasterFP_Point intersect = { 0, 0 };
+  int            recursive = 0;
+  if ( aP0.m_x >= aRasterFP->m_w && aP1.m_x >= aRasterFP->m_w )
+  {
+    aP0.m_x = aP1.m_x = (float)aRasterFP->m_w;
+    dxdy              = 0;
+  }
+  else if ( aP0.m_x <= 0 && aP1.m_x <= 0 )
+  {
+    aP0.m_x = aP1.m_x = 0;
+    dxdy              = 0;
+  }
+  else if ( ( aP0.m_x < 0 ) != ( aP1.m_x < 0 ) )
+  {
+    intersect.m_x = 0;
+    intersect.m_y = aP1.m_y - aP1.m_x / dxdy;
+    recursive     = 1;
+  }
+  else if ( ( aP0.m_x > aRasterFP->m_w ) != ( aP1.m_x > aRasterFP->m_w ) )
+  {
+    intersect.m_x = (float)aRasterFP->m_w;
+    intersect.m_y = aP0.m_y + ( aRasterFP->m_w - aP0.m_x ) / dxdy;
+    recursive     = 1;
+  }
+  if ( recursive )
+  {
+    aP0.m_x += aRasterFP->m_origin_x;
+    aP0.m_y += aRasterFP->m_origin_y;
+    aP1.m_x += aRasterFP->m_origin_x;
+    aP1.m_y += aRasterFP->m_origin_y;
+    intersect.m_x += aRasterFP->m_origin_x;
+    intersect.m_y += aRasterFP->m_origin_y;
+    if ( dir == 1 )
+    {
+      RasterFP_DrawLine( aRasterFP, aP0, intersect );
+      RasterFP_DrawLine( aRasterFP, intersect, aP1 );
+    }
+    else
+    {
+      RasterFP_DrawLine( aRasterFP, aP1, intersect );
+      RasterFP_DrawLine( aRasterFP, intersect, aP0 );
+    }
+    return;
+  }
+
+  float  x       = aP0.m_x;
+  int    y0      = (int)aP0.m_y;
+  int    y_limit = (int)ceil( aP1.m_y );
+  float* m_a     = aRasterFP->m_a;
+  for ( int y = y0; y < y_limit; y++ )
+  {
+    int   linestart = y * aRasterFP->m_w;
+    float dy        = fmin( y + 1.0f, aP1.m_y ) - fmax( (float)y, aP0.m_y );
+    float xnext     = x + dxdy * dy;
+    float d         = dy * dir;
+
+    float x0, x1;
+    if ( x < xnext )
+    {
+      x0 = x;
+      x1 = xnext;
+    }
+    else
+    {
+      x0 = xnext;
+      x1 = x;
+    }
+
+    /*
+    It's possible for x0 to be negative on the last scanline because of
+    floating-point inaccuracy That would cause an out-of-bounds array access at
+    index -1.
+    */
+    float x0floor = x0 <= 0.0f ? 0.0f : (float)floor( x0 );
+
+    int   x0i    = (int)x0floor;
+    float x1ceil = (float)ceil( x1 );
+    int   x1i    = (int)x1ceil;
+    if ( x1i <= x0i + 1 )
+    {
+      float xmf = 0.5f * ( x + xnext ) - x0floor;
+      m_a[linestart + x0i] += d - d * xmf;
+      m_a[linestart + ( x0i + 1 )] += d * xmf;
+    }
+    else
+    {
+      float s   = 1.0f / ( x1 - x0 );
+      float x0f = x0 - x0floor;
+      float a0  = 0.5f * s * ( 1.0f - x0f ) * ( 1.0f - x0f );
+      float x1f = x1 - x1ceil + 1.0f;
+      float am  = 0.5f * s * x1f * x1f;
+      m_a[linestart + x0i] += d * a0;
+      if ( x1i == x0i + 2 )
+        m_a[linestart + ( x0i + 1 )] += d * ( 1.0f - a0 - am );
+      else
+      {
+        float a1 = s * ( 1.5f - x0f );
+        m_a[linestart + ( x0i + 1 )] += d * ( a1 - a0 );
+        for ( int xi = x0i + 2; xi < x1i - 1; xi++ )
+          m_a[linestart + xi] += d * s;
+        float a2 = a1 + ( x1i - x0i - 3 ) * s;
+        m_a[linestart + ( x1i - 1 )] += d * ( 1.0f - a2 - am );
+      }
+      m_a[linestart + x1i] += d * am;
+    }
+    x = xnext;
+  }
+}
+
+
+
+
+
+static int
+dense_conic_to( const FT_Vector* control,
+               const FT_Vector* to,
+               RasterFP* aRasterFP)
+{
+  RasterFP_Point controlP = {control->x, control->y};
+  RasterFP_Point toP = {to->x, to->y};
+  RasterFP_DrawQuadratic( aRasterFP, aRasterFP->last_point,  controlP, toP );
+  return 0;
+}
+
+void
+RasterFP_DrawQuadratic( RasterFP*      aRasterFP,
+                        RasterFP_Point aP0,
+                        RasterFP_Point aP1,
+                        RasterFP_Point aP2 )
+{
+  assert( aRasterFP );
+
+  /*
+  Calculate devsq as the square of four times the
+  distance from the control point to the midpoint of the curve.
+  This is the place at which the curve is furthest from the
+  line joining the control points.
+
+  4 x point on curve = p0 + 2p1 + p2
+  4 x midpoint = 4p1
+
+  The division by four is omitted to save time.
+  */
+  float devx  = aP0.m_x - aP1.m_x - aP1.m_x + aP2.m_x;
+  float devy  = aP0.m_y - aP1.m_y - aP1.m_y + aP2.m_y;
+  float devsq = devx * devx + devy * devy;
+
+  if ( devsq < 0.333f )
+  {
+    RasterFP_DrawLine( aRasterFP, aP0, aP2 );
+    return;
+  }
+
+  /*
+  According to Raph Levien, the reason for the subdivision by n (instead of
+  recursive division by the Casteljau system) is that "I expect the flatness
+  computation to be semi-expensive (it's done once rather than on each 
potential
+  subdivision) and also because you'll often get fewer subdivisions. Taking a
+  circular arc as a simplifying assumption, where I get n, a recursive approach
+  would get 2^ceil(lg n), which, if I haven't made any horrible mistakes, is
+  expected to be 33% more in the limit".
+  */
+
+  const float    tol    = 3.0f;
+  int            n      = (int)floor( sqrt( sqrt( tol * devsq ) ) );
+  RasterFP_Point p      = aP0;
+  float          nrecip = 1.0f / ( n + 1.0f );
+  float          t      = 0.0f;
+  for ( int i = 0; i < n; i++ )
+  {
+    t += nrecip;
+    RasterFP_Point next = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
+    RasterFP_DrawLine( aRasterFP, p, next );
+    p = next;
+  }
+
+  RasterFP_DrawLine( aRasterFP, p, aP2 );
+}
+
+
+
+
+
+static int
+dense_cubic_to( const FT_Vector* control1,
+               const FT_Vector* control2,
+               const FT_Vector* to,
+               RasterFP* aRasterFP )
+{
+
+  RasterFP_Point ap1 = {control1->x, control1->y};
+  RasterFP_Point ap2 = {control2->x, control2->y};
+  RasterFP_Point ap3 = {to->x, to->y};
+
+
+  RasterFP_DrawCubic( aRasterFP, aRasterFP->last_point, ap1, ap2, ap3 );
+  return 0;
+}
+
+void
+RasterFP_DrawCubic( RasterFP*      aRasterFP,
+                    RasterFP_Point aP0,
+                    RasterFP_Point aP1,
+                    RasterFP_Point aP2,
+                    RasterFP_Point aP3 )
+{
+  assert( aRasterFP );
+
+  float devx   = aP0.m_x - aP1.m_x - aP1.m_x + aP2.m_x;
+  float devy   = aP0.m_y - aP1.m_y - aP1.m_y + aP2.m_y;
+  float devsq0 = devx * devx + devy * devy;
+  devx         = aP1.m_x - aP2.m_x - aP2.m_x + aP3.m_x;
+  devy         = aP1.m_y - aP2.m_y - aP2.m_y + aP3.m_y;
+  float devsq1 = devx * devx + devy * devy;
+  float devsq  = fmax( devsq0, devsq1 );
+
+  if ( devsq < 0.333f )
+  {
+    RasterFP_DrawLine( aRasterFP, aP0, aP3 );
+    return;
+  }
+
+  const float    tol    = 3.0f;
+  int            n      = (int)floor( sqrt( sqrt( tol * devsq ) ) );
+  RasterFP_Point p      = aP0;
+  float          nrecip = 1.0f / ( n + 1.0f );
+  float          t      = 0.0f;
+  for ( int i = 0; i < n; i++ )
+  {
+    t += nrecip;
+    RasterFP_Point a    = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
+    RasterFP_Point b    = Lerp( t, Lerp( t, aP1, aP2 ), Lerp( t, aP2, aP3 ) );
+    RasterFP_Point next = Lerp( t, a, b );
+    RasterFP_DrawLine( aRasterFP, p, next );
+    p = next;
+  }
+
+  RasterFP_DrawLine( aRasterFP, p, aP3 );
+}
+
+
+
+
+static int
+dense_raster_new( FT_Memory memory, dense_PRaster* araster )
+{
+  FT_Error     error;
+  dense_PRaster raster;
+
+  if ( !FT_NEW( raster ) )
+    raster->memory = memory;
+
+  *araster = raster;
+
+  return error;
+}
+
+static void
+dense_raster_done( FT_Raster raster )
+{
+  FT_Memory memory = (FT_Memory)( (dense_PRaster)raster )->memory;
+
+  FT_FREE( raster );
+}
+
+
+static void
+dense_raster_reset( FT_Raster      raster,
+                   unsigned char* pool_base,
+                   unsigned long  pool_size )
+{
+  FT_UNUSED( raster );
+  FT_UNUSED( pool_base );
+  FT_UNUSED( pool_size );
+}
+
+static int
+dense_raster_set_mode( FT_Raster raster, unsigned long mode, void* args )
+{
+  FT_UNUSED( raster );
+  FT_UNUSED( mode );
+  FT_UNUSED( args );
+
+  return 0; /* nothing to do */
+}
+
+FT_DEFINE_OUTLINE_FUNCS(
+    func_interface,
+
+    (FT_Outline_MoveTo_Func)dense_move_to,   /* move_to  */
+    (FT_Outline_LineTo_Func)dense_line_to,   /* line_to  */
+    (FT_Outline_ConicTo_Func)dense_conic_to, /* conic_to */
+    (FT_Outline_CubicTo_Func)dense_cubic_to, /* cubic_to */
+
+    0, /* shift    */
+    0  /* delta    */
+)
+
+
+
+
+
+
+
+
+static int
+gray_convert_glyph_inner( RAS_ARG, int continued )
+{
+  int error;
+
+  if ( ft_setjmp( ras.jump_buffer ) == 0 )
+  {
+    if ( continued )
+      FT_Trace_Disable();
+    error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
+    if ( continued )
+      FT_Trace_Enable();
+
+    FT_TRACE7( ( "band [%d..%d]: %ld cell%s remaining/\n", ras.min_ey,
+                 ras.max_ey, ras.cell_null - ras.cell_free,
+                 ras.cell_null - ras.cell_free == 1 ? "" : "s" ) );
+  }
+  else
+  {
+    error = FT_THROW( Raster_Overflow );
+
+    FT_TRACE7( ( "band [%d..%d]: to be bisected\n", ras.min_ey, ras.max_ey ) );
+  }
+
+  return error;
+}
+
+static int gray_convert_glyph( RAS_ARG )
+{
+  const TCoord yMin = ras.min_ey;
+  const TCoord yMax = ras.max_ey;
+
+  TCell   buffer[FT_MAX_GRAY_POOL];
+  size_t  height = (size_t)( yMax - yMin );
+  size_t  n      = FT_MAX_GRAY_POOL / 8;
+  TCoord  y;
+  TCoord  bands[32]; /* enough to accommodate bisections */
+  TCoord* band;
+
+  int continued = 0;
+
+  /* Initialize the null cell at the end of the poll. */
+  ras.cell_null        = buffer + FT_MAX_GRAY_POOL - 1;
+  ras.cell_null->x     = CELL_MAX_X_VALUE;
+  ras.cell_null->area  = 0;
+  ras.cell_null->cover = 0;
+  ras.cell_null->next  = NULL;
+
+  /* set up vertical bands */
+  ras.ycells = (PCell*)buffer;
+
+  if ( height > n )
+  {
+    /* two divisions rounded up */
+    n      = ( height + n - 1 ) / n;
+    height = ( height + n - 1 ) / n;
+  }
+
+  for ( y = yMin; y < yMax; )
+  {
+    ras.min_ey = y;
+    y += height;
+    ras.max_ey = FT_MIN( y, yMax );
+
+    band    = bands;
+    band[1] = ras.min_ey;
+    band[0] = ras.max_ey;
+
+    do
+    {
+      TCoord width = band[0] - band[1];
+      TCoord w;
+      int    error;
+
+      for ( w = 0; w < width; ++w )
+        ras.ycells[w] = ras.cell_null;
+
+      /* memory management: skip ycells */
+      n = ( width * sizeof( PCell ) + sizeof( TCell ) - 1 ) / sizeof( TCell );
+
+      ras.cell_free = buffer + n;
+      ras.cell      = ras.cell_null;
+      ras.min_ey    = band[1];
+      ras.max_ey    = band[0];
+      ras.count_ey  = width;
+
+      error     = gray_convert_glyph_inner( RAS_VAR, continued );
+      continued = 1;
+
+      if ( !error )
+      {
+        if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */
+          gray_sweep_direct( RAS_VAR );
+        else
+          gray_sweep( RAS_VAR );
+        band--;
+        continue;
+      }
+      else if ( error != Smooth_Err_Raster_Overflow )
+        return error;
+
+      /* render pool overflow; we will reduce the render band by half */
+      width >>= 1;
+
+      /* this should never happen even with tiny rendering pool */
+      if ( width == 0 )
+      {
+        FT_TRACE7( ( "gray_convert_glyph: rotten glyph\n" ) );
+        return FT_THROW( Raster_Overflow );
+      }
+
+      band++;
+      band[1] = band[0];
+      band[0] += width;
+    } while ( band >= bands );
+  }
+
+  return Smooth_Err_Ok;
+}
+
+static int
+dense_raster_render( FT_Raster raster, const FT_Raster_Params* params )
+{
+  const FT_Outline* outline    = (const FT_Outline*)params->source;
+  const FT_Bitmap*  target_map = params->target;
+
+#ifndef FT_STATIC_RASTER
+  gray_TWorker worker[1];
+#endif
+
+  if ( !raster )
+    return FT_THROW( Invalid_Argument );
+
+  /* this version does not support monochrome rendering */
+  if ( !( params->flags & FT_RASTER_FLAG_AA ) )
+    return FT_THROW( Cannot_Render_Glyph );
+
+  if ( !outline )
+    return FT_THROW( Invalid_Outline );
+
+  /* return immediately if the outline is empty */
+  if ( outline->n_points == 0 || outline->n_contours <= 0 )
+    return Smooth_Err_Ok;
+
+  if ( !outline->contours || !outline->points )
+    return FT_THROW( Invalid_Outline );
+
+  if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+    return FT_THROW( Invalid_Outline );
+
+  ras.outline = *outline;
+
+  if ( params->flags & FT_RASTER_FLAG_DIRECT )
+  {
+    if ( !params->gray_spans )
+      return Smooth_Err_Ok;
+
+    ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
+    ras.render_span_data = params->user;
+
+    ras.min_ex = params->clip_box.xMin;
+    ras.min_ey = params->clip_box.yMin;
+    ras.max_ex = params->clip_box.xMax;
+    ras.max_ey = params->clip_box.yMax;
+  }
+  else
+  {
+    /* if direct mode is not set, we must have a target bitmap */
+    if ( !target_map )
+      return FT_THROW( Invalid_Argument );
+
+    /* nothing to do */
+    if ( !target_map->width || !target_map->rows )
+      return Smooth_Err_Ok;
+
+    if ( !target_map->buffer )
+      return FT_THROW( Invalid_Argument );
+
+    if ( target_map->pitch < 0 )
+      ras.target.origin = target_map->buffer;
+    else
+      ras.target.origin =
+          target_map->buffer +
+          ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
+
+    ras.target.pitch = target_map->pitch;
+
+    ras.render_span      = (FT_Raster_Span_Func)NULL;
+    ras.render_span_data = NULL;
+
+    ras.min_ex = 0;
+    ras.min_ey = 0;
+    ras.max_ex = (FT_Pos)target_map->width;
+    ras.max_ey = (FT_Pos)target_map->rows;
+  }
+
+  /* exit if nothing to do */
+  if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
+    return Smooth_Err_Ok;
+
+  return gray_convert_glyph( RAS_VAR );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+FT_DEFINE_RASTER_FUNCS(
+    ft_dense_raster,
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Raster_New_Func)dense_raster_new,           /* raster_new      */
+    (FT_Raster_Reset_Func)dense_raster_reset,       /* raster_reset    */
+    (FT_Raster_Set_Mode_Func)dense_raster_set_mode, /* raster_set_mode */
+    (FT_Raster_Render_Func)dense_raster_render,     /* raster_render   */
+    (FT_Raster_Done_Func)dense_raster_done          /* raster_done     */
+)
+
 /* END */
\ No newline at end of file
diff --git a/src/dense/ftdense.h b/src/dense/ftdense.h
index 9321aa3db..bf208d146 100644
--- a/src/dense/ftdense.h
+++ b/src/dense/ftdense.h
@@ -2,6 +2,148 @@
 #ifndef FTDENSE_H_
 #define FTDENSE_H_
 
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include <freetype/ftimage.h>
+
+
+FT_BEGIN_HEADER
+
+/**************************************************************************
+ *
+ * @struct:
+ *   SDF_Raster_Params
+ *
+ * @description:
+ *   This struct must be passed to the raster render function
+ *   @FT_Raster_RenderFunc instead of @FT_Raster_Params because the
+ *   rasterizer requires some additional information to render properly.
+ *
+ * @fields:
+ *   root ::
+ *     The native raster parameters structure.
+ *
+ *   spread ::
+ *     This is an essential parameter/property required by the renderer.
+ *     `spread` defines the maximum unsigned value that is present in the
+ *     final SDF output.  For the default value check file
+ *     `ftsdfcommon.h`.
+ *
+ *   flip_sign ::
+ *     By default positive values indicate positions inside of contours,
+ *     i.e., filled by a contour.  If this property is true then that
+ *     output will be the opposite of the default, i.e., negative values
+ *     indicate positions inside of contours.
+ *
+ *   flip_y ::
+ *     Setting this parameter to true maked the output image flipped
+ *     along the y-axis.
+ *
+ *   overlaps ::
+ *     Set this to true to generate SDF for glyphs having overlapping
+ *     contours.  The overlapping support is limited to glyphs that do not
+ *     have self-intersecting contours.  Also, removing overlaps require a
+ *     considerable amount of extra memory; additionally, it will not work
+ *     if generating SDF from bitmap.
+ *
+ * @note:
+ *   All properties are valid for both the 'sdf' and 'bsdf' renderers; the
+ *   exception is `overlaps`, which gets ignored by the 'bsdf' renderer.
+ *
+ */
+typedef struct DENSE_Raster_Params_
+{
+  FT_Raster_Params root;
+  FT_UInt          spread;
+  FT_Bool          flip_sign;
+  FT_Bool          flip_y;
+  FT_Bool          overlaps;
+
+} DENSE_Raster_Params;
+
+/* rasterizer to convert outline to SDF */
+FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_dense_raster;
+
+/**
+RASTER_FP
+
+A floating-point anti-aliasing renderer.
+Graham Asher, August 2016.
+
+Most of this code is derived from Raph Levien's font-rs code in the Rust
+language, which is licensed under the Apache License, version 2.0.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  typedef struct
+  {
+    float m_x;
+    float m_y;
+  } RasterFP_Point;
+
+  typedef struct
+  {
+    /** The array used to store signed area differences. */
+    float* m_a;
+    /** The number of elements in m_a. */
+    int m_a_size;
+    /** The width of the current raster in pixels. */
+    int m_w;
+    /** The height of the current raster in pixels. */
+    int m_h;
+    /** The x origin of the raster. */
+    int m_origin_x;
+    /** The y origin of the raster. */
+    int m_origin_y;
+
+    RasterFP_Point last_point;
+  } RasterFP;
+
+  void RasterFP_Create( RasterFP* aRasterFP );
+  void RasterFP_StartRasterizing( RasterFP* aRasterFP,
+                                  int       aOriginX,
+                                  int       aOriginY,
+                                  int       aWidth,
+                                  int       aHeight );
+  void RasterFP_Destroy( RasterFP* aRasterFP );
+  void RasterFP_DrawLine( RasterFP*      aRasterFP,
+                          RasterFP_Point aP0,
+                          RasterFP_Point aP1 );
+  void RasterFP_DrawQuadratic( RasterFP*      aRasterFP,
+                               RasterFP_Point aP0,
+                               RasterFP_Point aP1,
+                               RasterFP_Point aP2 );
+  void RasterFP_DrawCubic( RasterFP*      aRasterFP,
+                           RasterFP_Point aP0,
+                           RasterFP_Point aP1,
+                           RasterFP_Point aP2,
+                           RasterFP_Point aP3 );
+  void RasterFP_GetBitmap( RasterFP* aRasterFP, unsigned char* aBitmap );
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+
+FT_END_HEADER
+
 #endif /* FTDENSE_H_ */
 
 /* END */
diff --git a/src/dense/ftdenserend.c b/src/dense/ftdenserend.c
index a7ca8ca59..75c5771df 100644
--- a/src/dense/ftdenserend.c
+++ b/src/dense/ftdenserend.c
@@ -1,3 +1,360 @@
 /** The 'dense' renderer */
 
+#include "ftdenserend.h"
+#include <freetype/ftbitmap.h>
+#include <freetype/ftoutln.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/services/svprop.h>
+#include "ftdense.h"
+
+#include "ftdenseerrs.h"
+
+/**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode.  It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT dense
+
+/**************************************************************************
+ *
+ * macros and default property values
+ *
+ */
+#define DENSE_RENDERER( rend ) ( (DENSE_Renderer)rend )
+
+/**************************************************************************
+ *
+ * for setting properties
+ *
+ */
+
+/* property setter function */
+static FT_Error
+dense_property_set( FT_Module   module,
+                    const char* property_name,
+                    const void* value,
+                    FT_Bool     value_is_string )
+{
+  FT_Error       error  = FT_Err_Ok;
+  DENSE_Renderer render = DENSE_RENDERER( FT_RENDERER( module ) );
+
+  FT_UNUSED( value_is_string );
+
+  if ( ft_strcmp( property_name, "spread" ) == 0 )
+  {
+    // FT_Int val = *(const FT_Int*)value;
+    // if ( val > MAX_SPREAD || val < MIN_SPREAD )
+    // {
+    //   FT_TRACE0(
+    //       ( "[sdf] dense_property_set:"
+    //         " the `spread' property can have a value\n" ) );
+    //   FT_TRACE0(
+    //       ( "                       "
+    //         " within range [%d, %d] (value provided: %d)\n",
+    //         MIN_SPREAD, MAX_SPREAD, val ) );
+    //
+    //   error = FT_THROW( Invalid_Argument );
+    //   goto Exit;
+    // }
+    //
+    // render->spread = (FT_UInt)val;
+    // FT_TRACE7(
+    //     ( "[sdf] dense_property_set:"
+    //       " updated property `spread' to %d\n",
+    //       val ) );
+  }
+
+  else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
+  {
+    ;
+  }
+
+  else
+  {
+    FT_TRACE0(
+        ( "[dense] dense_property_set:"
+          " missing property `%s'\n",
+          property_name ) );
+    error = FT_THROW( Missing_Property );
+  }
+
+Exit:
+  return error;
+}
+
+/* property getter function */
+static FT_Error
+dense_property_get( FT_Module module, const char* property_name, void* value )
+{
+  FT_Error       error  = FT_Err_Ok;
+  DENSE_Renderer render = DENSE_RENDERER( FT_RENDERER( module ) );
+
+  if ( ft_strcmp( property_name, "spread" ) == 0 )
+  {
+    // FT_Int* val = (FT_Int*)value;
+
+    // *val = render->spread;
+  }
+
+  else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
+  {
+    ;
+  }
+
+  else
+  {
+    FT_TRACE0(
+        ( "[dense] dense_property_get:"
+          " missing property `%s'\n",
+          property_name ) );
+    error = FT_THROW( Missing_Property );
+  }
+
+  return error;
+}
+
+FT_DEFINE_SERVICE_PROPERTIESREC(
+    dense_service_properties,
+
+    (FT_Properties_SetFunc)dense_property_set,  /* set_property */
+    (FT_Properties_GetFunc)dense_property_get ) /* get_property */
+
+FT_DEFINE_SERVICEDESCREC1( dense_services,
+
+                           FT_SERVICE_ID_PROPERTIES,
+                           &dense_service_properties )
+
+static FT_Module_Interface
+ft_dense_requester( FT_Renderer render, const char* module_interface )
+{
+  FT_UNUSED( render );
+
+  return ft_service_list_lookup( dense_services, module_interface );
+}
+
+/**************************************************************************
+ *
+ * interface functions
+ *
+ */
+
+static FT_Error
+ft_dense_init( FT_Renderer render )
+{
+  DENSE_Renderer dense_render = DENSE_RENDERER( render );
+
+  //   dense_render->spread    = 0;
+  //   dense_render->flip_sign = 0;
+  //   dense_render->flip_y    = 0;
+  //   dense_render->overlaps  = 0;
+
+  return FT_Err_Ok;
+}
+
+static void
+ft_dense_done( FT_Renderer render )
+{
+  FT_UNUSED( render );
+}
+
+/* generate signed distance field from a glyph's slot image */
+static FT_Error
+ft_dense_render( FT_Renderer      module,
+                 FT_GlyphSlot     slot,
+                 FT_Render_Mode   mode,
+                 const FT_Vector* origin )
+{
+  FT_Error    error   = FT_Err_Ok;
+  FT_Outline* outline = &slot->outline;
+  FT_Bitmap*  bitmap  = &slot->bitmap;
+  FT_Memory   memory  = NULL;
+  FT_Renderer render  = NULL;
+
+  FT_Pos x_shift = 0;
+  FT_Pos y_shift = 0;
+
+  FT_Pos x_pad = 0;
+  FT_Pos y_pad = 0;
+
+  DENSE_Raster_Params params;
+  DENSE_Renderer      dense_module = DENSE_RENDERER( module );
+
+  render = &dense_module->root;
+  memory = render->root.memory;
+
+  /* check whether slot format is correct before rendering */
+  if ( slot->format != render->glyph_format )
+  {
+    error = FT_THROW( Invalid_Glyph_Format );
+    goto Exit;
+  }
+
+  /* check whether render mode is correct */
+  if ( mode != FT_RENDER_MODE_NORMAL )
+  {
+    FT_ERROR(
+        ( "[dense] ft_dense_render:"
+          " sdf module only render when"
+          " using `FT_RENDER_MODE_NORMAL'\n" ) );
+    error = FT_THROW( Cannot_Render_Glyph );
+    goto Exit;
+  }
+
+  /* deallocate the previously allocated bitmap */
+  if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+  {
+    FT_FREE( bitmap->buffer );
+    slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+  }
+
+  /* preset the bitmap using the glyph's outline;         */
+  /* the sdf bitmap is similar to an antialiased bitmap   */
+  /* with a slightly bigger size and different pixel mode */
+  if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) )
+  {
+    error = FT_THROW( Raster_Overflow );
+    goto Exit;
+  }
+
+  if ( !bitmap->rows || !bitmap->pitch )
+    goto Exit;
+
+  /* the padding will simply be equal to the `spread' */
+  x_pad = dense_module->spread;
+  y_pad = dense_module->spread;
+
+  /* apply the padding; will be in all the directions */
+  bitmap->rows += y_pad * 2;
+  bitmap->width += x_pad * 2;
+
+  /* ignore the pitch, pixel mode and set custom */
+  bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+  bitmap->pitch      = bitmap->width;
+  bitmap->num_grays  = 255;
+
+  /* allocate new buffer */
+  if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
+    goto Exit;
+
+  slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+
+  x_shift = 64 * -( slot->bitmap_left - x_pad );
+  y_shift = 64 * -( slot->bitmap_top + y_pad );
+  y_shift += 64 * (FT_Int)bitmap->rows;
+
+  if ( origin )
+  {
+    x_shift += origin->x;
+    y_shift += origin->y;
+  }
+
+  /* translate outline to render it into the bitmap */
+  if ( x_shift || y_shift )
+    FT_Outline_Translate( outline, x_shift, y_shift );
+
+  /* set up parameters */
+  params.root.target = bitmap;
+  params.root.source = outline;
+  params.root.flags  = FT_RASTER_FLAG_DEFAULT;
+  params.spread      = dense_module->spread;
+  params.flip_sign   = dense_module->flip_sign;
+  params.flip_y      = dense_module->flip_y;
+  params.overlaps    = dense_module->overlaps;
+
+  /* render the outline */
+  error =
+      render->raster_render( render->raster, (const FT_Raster_Params*)&params 
);
+
+Exit:
+  if ( !error )
+  {
+    /* the glyph is successfully rendered to a bitmap */
+    slot->format = FT_GLYPH_FORMAT_BITMAP;
+  }
+  else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+  {
+    FT_FREE( bitmap->buffer );
+    slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+  }
+
+  if ( x_shift || y_shift )
+    FT_Outline_Translate( outline, -x_shift, -y_shift );
+
+  return error;
+}
+
+/* transform the glyph using matrix and/or delta */
+static FT_Error
+ft_dense_transform( FT_Renderer      render,
+                    FT_GlyphSlot     slot,
+                    const FT_Matrix* matrix,
+                    const FT_Vector* delta )
+{
+  FT_Error error = FT_Err_Ok;
+
+  if ( slot->format != render->glyph_format )
+  {
+    error = FT_THROW( Invalid_Argument );
+    goto Exit;
+  }
+
+  if ( matrix )
+    FT_Outline_Transform( &slot->outline, matrix );
+
+  if ( delta )
+    FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+Exit:
+  return error;
+}
+
+/* return the control box of a glyph's outline */
+static void
+ft_dense_get_cbox( FT_Renderer render, FT_GlyphSlot slot, FT_BBox* cbox )
+{
+  FT_ZERO( cbox );
+
+  if ( slot->format == render->glyph_format )
+    FT_Outline_Get_CBox( &slot->outline, cbox );
+}
+
+/* set render specific modes or attributes */
+static FT_Error
+ft_dense_set_mode( FT_Renderer render, FT_ULong mode_tag, FT_Pointer data )
+{
+  /* pass it to the rasterizer */
+  return render->clazz->raster_class->raster_set_mode( render->raster, 
mode_tag,
+                                                       data );
+}
+
+FT_DEFINE_RENDERER(
+    ft_dense_renderer_class,
+
+    FT_MODULE_RENDERER,
+    sizeof( DENSE_Renderer_Module ),
+
+    "dense",
+    0x10000L,
+    0x20000L,
+
+    NULL,
+
+    (FT_Module_Constructor)ft_dense_init,
+    (FT_Module_Destructor)ft_dense_done,
+    (FT_Module_Requester)ft_dense_requester,
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)ft_dense_render,       /* render_glyph    */
+    (FT_Renderer_TransformFunc)ft_dense_transform, /* transform_glyph */
+    (FT_Renderer_GetCBoxFunc)ft_dense_get_cbox,    /* get_glyph_cbox  */
+    (FT_Renderer_SetModeFunc)ft_dense_set_mode,    /* set_mode        */
+
+    (FT_Raster_Funcs*)&ft_dense_raster /* raster_class    */
+)
+
 /* END */
\ No newline at end of file
diff --git a/src/dense/ftdenserend.h b/src/dense/ftdenserend.h
index 409f7fe8c..7f28eae6d 100644
--- a/src/dense/ftdenserend.h
+++ b/src/dense/ftdenserend.h
@@ -2,6 +2,79 @@
 #ifndef FTDENSEREND_H_
 #define FTDENSEREND_H_
 
+
+#include <freetype/ftmodapi.h>
+#include <freetype/ftrender.h>
+#include <freetype/internal/ftobjs.h>
+
+FT_BEGIN_HEADER
+
+/**************************************************************************
+ *
+ * @struct:
+ *   DENSE_Renderer_Module
+ *
+ * @description:
+ *   This struct extends the native renderer struct `FT_RendererRec`.  It
+ *   is basically used to store various parameters required by the
+ *   renderer and some additional parameters that can be used to tweak the
+ *   output of the renderer.
+ *
+ * @fields:
+ *   root ::
+ *     The native rendere struct.
+ *
+ *   spread ::
+ *     This is an essential parameter/property required by the renderer.
+ *     `spread` defines the maximum unsigned value that is present in the
+ *     final SDF output.  For the default value check file
+ *     `ftsdfcommon.h`.
+ *
+ *   flip_sign ::
+ *     By default positive values indicate positions inside of contours,
+ *     i.e., filled by a contour.  If this property is true then that
+ *     output will be the opposite of the default, i.e., negative values
+ *     indicate positions inside of contours.
+ *
+ *   flip_y ::
+ *     Setting this parameter to true makes the output image flipped
+ *     along the y-axis.
+ *
+ *   overlaps ::
+ *     Set this to true to generate SDF for glyphs having overlapping
+ *     contours.  The overlapping support is limited to glyphs that do not
+ *     have self-intersecting contours.  Also, removing overlaps require a
+ *     considerable amount of extra memory; additionally, it will not work
+ *     if generating SDF from bitmap.
+ *
+ * @note:
+ *   All properties except `overlaps` are valid for both the 'sdf' and
+ *   'bsdf' renderers.
+ *
+ */
+typedef struct DENSE_Renderer_Module_
+{
+  FT_RendererRec root;
+  FT_UInt        spread;
+  FT_Bool        flip_sign;
+  FT_Bool        flip_y;
+  FT_Bool        overlaps;
+
+} DENSE_Renderer_Module, *DENSE_Renderer;
+
+/**************************************************************************
+ *
+ * @renderer:
+ *   ft_sdf_renderer_class
+ *
+ * @description:
+ *   Renderer to convert @FT_Outline to signed distance fields.
+ *
+ */
+FT_DECLARE_RENDERER( ft_dense_renderer_class )
+
+FT_END_HEADER
+
 #endif /* FTDENSEREND_H_ */
 
 /* END */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]