forked from minhngoc25a/freetype2
Added things
This commit is contained in:
parent
e68cdd5f9e
commit
12ffde24a1
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"ftoutln.h": "c"
|
"ftoutln.h": "c",
|
||||||
|
"svprop.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,622 @@
|
||||||
/** The rasterizer for the 'dense' renderer */
|
/** 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 */
|
/* END */
|
|
@ -2,6 +2,148 @@
|
||||||
#ifndef FTDENSE_H_
|
#ifndef FTDENSE_H_
|
||||||
#define 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_ */
|
#endif /* FTDENSE_H_ */
|
||||||
|
|
||||||
/* END */
|
/* END */
|
||||||
|
|
|
@ -1,3 +1,360 @@
|
||||||
/** The 'dense' renderer */
|
/** 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*)¶ms );
|
||||||
|
|
||||||
|
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 */
|
/* END */
|
|
@ -2,6 +2,79 @@
|
||||||
#ifndef FTDENSEREND_H_
|
#ifndef FTDENSEREND_H_
|
||||||
#define 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_ */
|
#endif /* FTDENSEREND_H_ */
|
||||||
|
|
||||||
/* END */
|
/* END */
|
||||||
|
|
Loading…
Reference in New Issue