summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnurag Thakur <anurag105csec21@bpitindia.edu.in>2021-10-27 13:50:47 +0530
committerAnurag Thakur <anurag105csec21@bpitindia.edu.in>2022-10-04 03:16:11 +0530
commit63dd924394ebc4b72f8c780a97de68a24aed795c (patch)
treed13b51bcb531948eeeed6fb1f74aa296c02feb0f
parentf6a2237ff6af19b8af3fd12ad13068a6e52ab177 (diff)
downloadfreetype2-63dd924394ebc4b72f8c780a97de68a24aed795c.tar.gz
Added things
-rw-r--r--.vscode/settings.json3
-rw-r--r--src/dense/ftdense.c619
-rw-r--r--src/dense/ftdense.h142
-rw-r--r--src/dense/ftdenserend.c357
-rw-r--r--src/dense/ftdenserend.h73
5 files changed, 1193 insertions, 1 deletions
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 */