Added things

This commit is contained in:
Anurag Thakur 2021-10-27 13:50:47 +05:30
parent e68cdd5f9e
commit 12ffde24a1
5 changed files with 1193 additions and 1 deletions

View File

@ -1,5 +1,6 @@
{
"files.associations": {
"ftoutln.h": "c"
"ftoutln.h": "c",
"svprop.h": "c"
}
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */