Compare commits

...

11 Commits

Author SHA1 Message Date
Anurag Thakur
6b161ceb8a [dense] Add optimization for division
* src/dense/ftdense.c: FT_UDIV, FT_UDIVPREP macros taken from smooth
rasterizer, help optimize fixed-point division
2022-11-19 13:22:15 +05:30
Anurag Thakur
5d683228e7 [dense] Add optimization for vertical lines
* src/dense/ftdense.c: Optimize line drawing when a vertical line is encountered
2022-11-19 13:14:51 +05:30
Anurag Thakur
763f11088e [dense] Re-enable SIMD to work with fixed-point
* src/dense/ftdense.c: Use integer SIMD functions for accumulation

* src/dense/ftdense.h: Change types of FT26D6, FT20D12 to better fit
their usage
2022-11-19 13:05:14 +05:30
Anurag Thakur
cd2e6217f3 [dense] Migrate line drawing and accumulation to fixed-point
* src/dense/ftdense.h: (FT26D6, FT20D12): New typedefs

* src/dense/ftdense.c: dense_render_line, dense_render_glyph now
use fixed-point numbers for calculation

Disabled SIMD for now
2022-11-19 12:58:14 +05:30
Anurag Thakur
bdeb70bc18 [dense] Add SIMD support to rasterizer
* src/dense/ftdense: Use SSE4.1 for final accumulation step
(FT_SSE4_1): Macro which checks if SSE4.1 is available

* src/dense/rules.mk: Enable linking for SSE4.1
2022-11-19 12:34:43 +05:30
Anurag Thakur
03cc2183e0 [dense] Enable module compilation
* src/dense/ftdense.c: Redefine FT_SWAP to fix compilation error

* src/include/freetype/config/ftmodule.h: Added ft_dense_renderer_class

* src/dense/dense.c: Build single object of module

* modules.cfg: Added 'dense' RASTER_MODULE

* src/dense/module.mk, src/dense/rules.mk: Added Makefile

* CMakeLists.txt: Added 'dense.c' to compilation files
2022-11-19 11:06:36 +05:30
Anurag Thakur
4b77d947c5 [dense] Add drawing functions to rasterizer
* src/dense/ftdense.c: (dense_render_line, dense_render_quadratic,
dense_render_cubic, dense_render_glyph, dense_raster_render, Lerp):
New Functions
2022-11-19 10:45:39 +05:30
Anurag Thakur
f126946b6a [dense] Add rasterizer functions
* src/dense/ftdense.c: (ONE_PIXEL, TRUNC, UPSCALE, DOWNSCALE,
FT_SWAP, FT_MIN, FT_MAX, FT_ABS): New Macros

(dense_move_to, dense_line_to, dense_conic_to): Added outline
decomposing functions

(dense_raster_new, dense_raster_done, dense_raster_reset,
dense_raster_set_mode, dense_raster_render): Added interface
functions
2022-11-19 10:28:46 +05:30
Anurag Thakur
a3c327aa41 [dense] Add 'dense' renderer
* src/dense/ftdenserend.c: Add 'dense' renderer along with its interface
functions.

(ft_dense_set_mode, ft_dense_transform, ft_dense_get_cbox, ft_dense_init,
ft_dense_done, ft_dense_render)
2022-11-19 01:24:19 +05:30
Anurag Thakur
3b3c13d967 [dense] Populate headers for 'dense' module
* src/dense/ftdenserend.h (ft_dense_renderer_class): New Structures

* src/dense/ftdense.h (dense_worker): New Structure
(dense_render_line, dense_render_quadratic, dense_render_cubic): New
function declarations
(ft_dense_raster): Export dense raster funcs

* src/dense/ftdenseerrs.h: Add module error setup
2022-11-19 00:54:43 +05:30
Anurag Thakur
10f72058a3 [dense] Add files for new 'dense' module
Breakdown of what the files will contain

* src/dense/ftdenserend.c, src/dense/ftdenserend.h: The 'dense' renderer.

* src/dense/ftdense.c, src/dense/ftdense.h: The rasterizer for the
'dense' renderer.

* src/dense/ftdenseerrs.h: Common error defines.

* src/dense/dense.c: For building a single object of the entire module.
2022-11-18 13:18:54 +05:30
11 changed files with 988 additions and 0 deletions

View File

@ -405,6 +405,7 @@ set(BASE_SRCS
src/cache/ftcache.c
src/cff/cff.c
src/cid/type1cid.c
src/dense/dense.c
src/gzip/ftgzip.c
src/lzw/ftlzw.c
src/pcf/pcf.c

View File

@ -24,6 +24,7 @@ FT_USE_MODULE( FT_Module_Class, psaux_module_class )
FT_USE_MODULE( FT_Module_Class, psnames_module_class )
FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
FT_USE_MODULE( FT_Renderer_Class, ft_dense_renderer_class )
FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class )

View File

@ -93,6 +93,9 @@ HINTING_MODULES += pshinter
#### raster modules -- at least one is required for vector font formats
####
# Dense Rasterizer
RASTER_MODULES += dense
# Anti-aliasing rasterizer.
RASTER_MODULES += smooth

6
src/dense/dense.c Normal file
View File

@ -0,0 +1,6 @@
/** For building a single object of the entire module */
#define FT_MAKE_OPTION_SINGLE_OBJECT
#include "ftdense.c"
#include "ftdenserend.c"
/* END */

554
src/dense/ftdense.c Normal file
View File

@ -0,0 +1,554 @@
/** 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 <math.h>
#include "ftdense.h"
#include "ftdenseerrs.h"
#if defined( __SSE4_1__ ) || \
defined( __x86_64__ ) || \
defined( _M_AMD64 ) || \
( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 )
# define FT_SSE4_1 1
#else
# define FT_SSE4_1 0
#endif
#if FT_SSE4_1
#include <immintrin.h>
#endif
#define PIXEL_BITS 8
#define ONE_PIXEL ( 1 << PIXEL_BITS )
#define TRUNC( x ) (int)( ( x ) >> PIXEL_BITS )
#define UPSCALE( x ) ( ( x ) * ( ONE_PIXEL >> 6 ) )
#define DOWNSCALE( x ) ( ( x ) >> ( PIXEL_BITS - 6 ) )
#define FT_SWAP(a, b) { (a) = (a) + (b); (b) = (a) - (b); (a) = (a) - (b);}
#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) )
#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
// TODO: Fix types
#define FT_UDIVPREP( c, b ) \
FT26D6 b ## _r = c ? (FT26D6)0xFFFFFFFF / ( b ) : 0
#define FT_UDIV( a, b ) \
(FT26D6)( ( (FT26D6)( a ) * (FT26D6)( b ## _r ) ) >> 32 )
typedef struct dense_TRaster_
{
void* memory;
} dense_TRaster, *dense_PRaster;
/* Linear interpolation between P0 and P1 */
static FT_Vector
Lerp( float T, FT_Vector P0, FT_Vector P1 )
{
FT_Vector p;
p.x = P0.x + T * ( P1.x - P0.x );
p.y = P0.y + T * ( P1.y - P0.y );
return p;
}
static int
dense_move_to( const FT_Vector* to, dense_worker* worker )
{
FT_Pos x, y;
x = UPSCALE( to->x );
y = UPSCALE( to->y );
worker->prev_x = x;
worker->prev_y = y;
return 0;
}
static int
dense_line_to( const FT_Vector* to, dense_worker* worker )
{
dense_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
dense_move_to( to, worker );
return 0;
}
void
dense_render_line( dense_worker* worker, FT_Pos tox, FT_Pos toy )
{
FT26D6 fx = worker->prev_x>>2;
FT26D6 fy = worker->prev_y>>2;
FT26D6 from_x = fx;
FT26D6 from_y = fy;
FT26D6 tx = tox>>2;
FT26D6 ty = toy>>2;
if ( fy == ty )
return;
FT26D6 to_x = tx;
FT26D6 to_y = ty;
int dir = 1;
if ( from_y >= to_y )
{
dir = -1;
FT_SWAP(from_x, to_x);
FT_SWAP(from_y, to_y);
}
// Clip to the height.
if ( from_y >= worker->m_h<<6 || to_y <= 0 )
return;
FT26D6 deltax,deltay;
deltax = to_x - from_x;
deltay = to_y - from_y;
FT_UDIVPREP(from_x != to_x, deltax);
FT_UDIVPREP(from_y != to_y, deltay);
if ( from_y < 0 )
{
from_x -= from_y * deltax/deltay;
from_y = 0;
}
if ( to_y > worker->m_h<<6 )
{
to_x -= (( to_y - worker->m_h<<6 ) * deltax/deltay);
to_y = worker->m_h<<6;
}
if(deltax == 0){
FT26D6 x = from_x;
int x0i = x>>6;
FT26D6 x0floor = x0i<<6;
// y-coordinate of first pixel of line
int y0 = from_y>>6;
// y-coordinate of last pixel of line
int y_limit = (to_y + 0x3f)>>6;
FT20D12* m_a = worker->m_a;
for ( int y = y0; y < y_limit; y++ )
{
int linestart = y * worker->m_w;
FT26D6 dy = min( (y + 1)<<6, to_y ) - max( y<<6, from_y );
m_a[linestart + x0i] += dir*dy*(64 - x + x0floor);
m_a[linestart + ( x0i + 1 )] += dir*dy*(x-x0floor);
}
}
else
{
int x = from_x;
int y0 = from_y>>6;
int y_limit = (to_y + 0x3f)>>6;
FT20D12* m_a = worker->m_a;
for ( int y = y0; y < y_limit; y++ )
{
int linestart = y * worker->m_w;
FT26D6 dy = FT_MIN( (y + 1)<<6, to_y ) - FT_MAX( y<<6, from_y );
FT26D6 xnext = x + FT_UDIV((dy*deltax), deltay);
FT26D6 d = dy * dir;
FT26D6 x0, x1;
if ( x < xnext )
{
x0 = x;
x1 = xnext;
}
else
{
x0 = xnext;
x1 = x;
}
int x0i = x0>>6;
FT26D6 x0floor = x0i<<6;
int x1i = (x1+0x3f)>>6;
FT26D6 x1ceil = x1i <<6;
if ( x1i <= x0i + 1 )
{
FT26D6 xmf = ( ( x + xnext )>>1) - x0floor;
m_a[linestart + x0i] += d * ((1<<6) - xmf);
m_a[linestart + ( x0i + 1 )] += d * xmf;
}
else
{
FT26D6 oneOverS = x1 - x0;
FT_UDIVPREP(x1 != x0, oneOverS);
FT26D6 x0f = x0 - x0floor;
FT26D6 oneMinusX0f = (1<<6) - x0f;
FT26D6 a0 = FT_UDIV(((oneMinusX0f * oneMinusX0f) >> 1), oneOverS);
FT26D6 x1f = x1 - x1ceil + (1<<6);
FT26D6 am = FT_UDIV(((x1f * x1f) >> 1) , oneOverS);
m_a[linestart + x0i] += d * a0;
if ( x1i == x0i + 2 )
m_a[linestart + ( x0i + 1 )] += d * ( (1<<6) - a0 - am );
else
{
FT26D6 a1 = FT_UDIV((((1<<6) + (1<<5) - x0f) << 6) , oneOverS);
m_a[linestart + ( x0i + 1 )] += d * ( a1 - a0 );
FT26D6 dTimesS = FT_UDIV((d << 12) , oneOverS);
for ( FT26D6 xi = x0i + 2; xi < x1i - 1; xi++ )
m_a[linestart + xi] += dTimesS;
FT26D6 a2 = a1 + FT_UDIV((( x1i - x0i - 3 )<<12),oneOverS);
m_a[linestart + ( x1i - 1 )] += d * ( (1<<6) - a2 - am );
}
m_a[linestart + x1i] += d * am;
}
x = xnext;
}
}
}
static int
dense_conic_to( const FT_Vector* control,
const FT_Vector* to,
dense_worker* worker )
{
dense_render_quadratic( worker, control, to );
return 0;
}
void
dense_render_quadratic( dense_worker* worker,
FT_Vector* control,
FT_Vector* to )
{
/*
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.
*/
FT_Vector aP0 = { DOWNSCALE( worker->prev_x ), DOWNSCALE( worker->prev_y ) };
FT_Vector aP1 = { control->x, control->y };
FT_Vector aP2 = { to->x, to->y };
float devx = aP0.x - aP1.x - aP1.x + aP2.x;
float devy = aP0.y - aP1.y - aP1.y + aP2.y;
float devsq = devx * devx + devy * devy;
if ( devsq < 0.333f )
{
dense_line_to( &aP2, worker );
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 ) ) )/8;
FT_Vector p = aP0;
float nrecip = 1.0f / ( n + 1.0f );
float t = 0.0f;
for ( int i = 0; i < n; i++ )
{
t += nrecip;
FT_Vector next = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
dense_line_to(&next, worker );
p = next;
}
dense_line_to( &aP2, worker );
}
static int
dense_cubic_to( const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to,
dense_worker* worker )
{
dense_render_cubic( worker, control1, control2, to );
return 0;
}
void
dense_render_cubic( dense_worker* worker,
FT_Vector* control_1,
FT_Vector* control_2,
FT_Vector* to )
{
FT_Vector aP0 = { DOWNSCALE( worker->prev_x ), DOWNSCALE( worker->prev_y ) };
FT_Vector aP1 = { control_1->x, control_1->y };
FT_Vector aP2 = { control_2->x, control_2->y };
FT_Vector aP3 = { to->x, to->y };
float devx = aP0.x - aP1.x - aP1.x + aP2.x;
float devy = aP0.y - aP1.y - aP1.y + aP2.y;
float devsq0 = devx * devx + devy * devy;
devx = aP1.x - aP2.x - aP2.x + aP3.x;
devy = aP1.y - aP2.y - aP2.y + aP3.y;
float devsq1 = devx * devx + devy * devy;
float devsq = fmax( devsq0, devsq1 );
if ( devsq < 0.333f )
{
dense_render_line( worker, aP3.x, aP3.y );
return;
}
const float tol = 3.0f;
int n = (int)floor( sqrt( sqrt( tol * devsq ) ) ) / 8;
FT_Vector p = aP0;
float nrecip = 1.0f / ( n + 1.0f );
float t = 0.0f;
for ( int i = 0; i < n; i++ )
{
t += nrecip;
FT_Vector a = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
FT_Vector b = Lerp( t, Lerp( t, aP1, aP2 ), Lerp( t, aP2, aP3 ) );
FT_Vector next = Lerp( t, a, b );
dense_render_line( worker, next.x, next.y );
worker->prev_x = next.x;
worker->prev_y = next.y;
p = next;
}
dense_line_to( &aP3, worker );
}
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( dense_decompose_funcs,
(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
dense_render_glyph( dense_worker* worker, const FT_Bitmap* target )
{
FT_Error error = FT_Outline_Decompose( &( worker->outline ),
&dense_decompose_funcs, worker );
// Render into bitmap
const FT20D12* source = worker->m_a;
unsigned char* dest = target->buffer;
unsigned char* dest_end = target->buffer + worker->m_w * worker->m_h;
#if FT_SSE4_1
__m128i offset = _mm_setzero_si128();
__m128i mask = _mm_set1_epi32( 0x0c080400 );
for (int i = 0; i < worker->m_h*worker->m_w; i += 4)
{
// load 4 floats from source
__m128i x = _mm_load_si128( (__m128i*)&source[i] );
x = _mm_add_epi32( x, _mm_slli_si128( x, 4 ) );
x = _mm_add_epi32(
x, _mm_castps_si128( _mm_shuffle_ps( _mm_setzero_ps(),
_mm_castsi128_ps( x ), 0x40 ) ) );
// add the prefsum of previous 4 floats to all current floats
x = _mm_add_epi32( x, offset );
// take absolute value
__m128i y = _mm_abs_epi32( x ); // fabs(x)
// cap max value to 1
y = _mm_min_epi32( y, _mm_set1_epi32( 4080 ) );
// reduce to 255
y = _mm_srli_epi32( y, 4 );
// shuffle
y = _mm_shuffle_epi8( y, mask );
_mm_store_ss( (float*)&dest[i], (__m128)y );
// store the current prefix sum in offset
offset = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps( x ),
_mm_castsi128_ps( x ),
_MM_SHUFFLE( 3, 3, 3, 3 ) ) );
}
#else /* FT_SSE4_1 */
FT20D12 value = 0;
while ( dest < dest_end )
{
value += *source++;
if(value > 0){
int n = value >>4;
if(n>255)n=255;
*dest = (unsigned char)n;
}else{
*dest = 0;
}
dest++;
}
#endif /* FT_SSE4_1 */
free(worker->m_a);
return error;
}
static int
dense_raster_render( FT_Raster raster, const FT_Raster_Params* params )
{
const FT_Outline* outline = (const FT_Outline*)params->source;
FT_Bitmap* target_map = params->target;
dense_worker worker[1];
if ( !raster )
return FT_THROW( Invalid_Argument );
if ( !outline )
return FT_THROW( Invalid_Outline );
worker->outline = *outline;
if ( !target_map )
return FT_THROW( Invalid_Argument );
/* nothing to do */
if ( !target_map->width || !target_map->rows )
return 0;
if ( !target_map->buffer )
return FT_THROW( Invalid_Argument );
worker->m_origin_x = 0;
worker->m_origin_y = 0;
worker->m_w = target_map->pitch;
worker->m_h = target_map->rows;
int size = worker->m_w * worker->m_h + 4;
worker->m_a = malloc( sizeof( FT20D12 ) * size );
worker->m_a_size = size;
memset( worker->m_a, 0, ( sizeof( FT20D12 ) * size ) );
/* exit if nothing to do */
if ( worker->m_w <= worker->m_origin_x || worker->m_h <= worker->m_origin_y )
{
return 0;
}
// Invert the pitch to account for different +ve y-axis direction in dense array
// (maybe temporary solution)
target_map->pitch *= -1;
return dense_render_glyph( worker, target_map );
}
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 */

63
src/dense/ftdense.h Normal file
View File

@ -0,0 +1,63 @@
/* Dense rasterizer header*/
#ifndef FTDENSE_H_
#define FTDENSE_H_
#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/ftimage.h>
FT_BEGIN_HEADER
#ifndef FT_EXPORT_VAR
#define FT_EXPORT_VAR( x ) extern x
#endif
FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_dense_raster;
#ifdef __cplusplus
extern "C"
{
#endif
typedef signed long FT26D6; /* 26.6 fixed-point representation */
typedef signed int FT20D12; /* 20.12 fixed-point representation */
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;
FT_Pos prev_x, prev_y;
FT_Outline outline;
} dense_worker;
void dense_render_line( dense_worker* worker, FT_Pos to_x, FT_Pos to_y );
void dense_render_quadratic( dense_worker* worker,
FT_Vector* control,
FT_Vector* to );
void dense_render_cubic( dense_worker* worker,
FT_Vector* control_1,
FT_Vector* control_2,
FT_Vector* to );
#ifdef __cplusplus
} // extern "C"
#endif
FT_END_HEADER
#endif /* FTDENSE_H_ */
/* END */

17
src/dense/ftdenseerrs.h Normal file
View File

@ -0,0 +1,17 @@
/* Dense Renderer Error Codes */
#ifndef FTDENSEERRS_H_
#define FTDENSEERRS_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX Dense_Err_
#define FT_ERR_BASE FT_Mod_Err_Dense
#include <freetype/fterrors.h>
#endif /* FTDENSEERRS_H_ */
/* END */

220
src/dense/ftdenserend.c Normal file
View File

@ -0,0 +1,220 @@
/** The 'dense' renderer */
#include <freetype/ftoutln.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#include "ftdenserend.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
/**************************************************************************
*
* interface functions
*
*/
/* 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 );
}
/* 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 );
}
static FT_Error
ft_dense_init( FT_Renderer render )
{
return FT_Err_Ok;
}
static void
ft_dense_done( FT_Renderer render )
{
FT_UNUSED( render );
}
/* generate bitmap from a glyph's slot image */
static FT_Error
ft_dense_render( FT_Renderer render,
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_FREE and FT_ALLOC_MULT macros need a variable named 'memory' */
FT_Memory memory = render->root.memory;
FT_Pos x_shift = 0;
FT_Pos y_shift = 0;
FT_Raster_Params params;
/* check whether slot format is correct before rendering */
if ( slot->format != render->glyph_format )
{
error = FT_THROW( Invalid_Glyph_Format );
goto Exit;
}
/* check mode */
if ( mode != FT_RENDER_MODE_NORMAL &&
mode != FT_RENDER_MODE_LIGHT &&
mode != FT_RENDER_MODE_LCD &&
mode != FT_RENDER_MODE_LCD_V )
{
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 */
if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
{
error = FT_THROW( Raster_Overflow );
goto Exit;
}
if ( !bitmap->rows || !bitmap->pitch )
goto Exit;
/* allocate new one */
if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
goto Exit;
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
/* Calculate shift in 26.6 format */
x_shift = 64 * -slot->bitmap_left;
y_shift = 64 * -slot->bitmap_top;
if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
y_shift += 64 * (FT_Int)bitmap->rows / 3;
else
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.target = bitmap;
params.source = outline;
/* 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;
}
FT_DEFINE_RENDERER(
ft_dense_renderer_class,
FT_MODULE_RENDERER,
sizeof( FT_RendererRec ),
"dense",
0x10000L,
0x20000L,
NULL,
(FT_Module_Constructor)ft_dense_init,
(FT_Module_Destructor)ft_dense_done,
(FT_Module_Requester)NULL,
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 */

27
src/dense/ftdenserend.h Normal file
View File

@ -0,0 +1,27 @@
/* Dense renderer interface (specification) */
#ifndef FTDENSEREND_H_
#define FTDENSEREND_H_
#include <freetype/ftmodapi.h>
#include <freetype/ftrender.h>
#include <freetype/internal/ftobjs.h>
FT_BEGIN_HEADER
/**************************************************************************
*
* @renderer:
* ft_dense_renderer_class
*
* @description:
* Renderer to convert @FT_Outline to bitmaps.
*
*/
FT_DECLARE_RENDERER( ft_dense_renderer_class )
FT_END_HEADER
#endif /* FTDENSEREND_H_ */
/* END */

23
src/dense/module.mk Normal file
View File

@ -0,0 +1,23 @@
#
# FreeType 2 smooth renderer module definition
#
# Copyright (C) 1996-2021 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.
FTMODULE_H_COMMANDS += DENSE_RENDERER
define DENSE_RENDERER
$(OPEN_DRIVER) FT_Renderer_Class, ft_dense_renderer_class $(CLOSE_DRIVER)
$(ECHO_DRIVER)dense $(ECHO_DRIVER_DESC)anti-aliased dense renderer$(ECHO_DRIVER_DONE)
endef
# EOF

73
src/dense/rules.mk Normal file
View File

@ -0,0 +1,73 @@
#
# FreeType 2 DENSE renderer module build rules
#
# Copyright (C) 1996-2021 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.
# DENSE driver directory
#
DENSE_DIR := $(SRC_DIR)/dense
# compilation flags for the driver
#
DENSE_COMPILE := $(CC) $(ANSIFLAGS) \
$I$(subst /,$(COMPILER_SEP),$(DENSE_DIR)) \
$(INCLUDE_FLAGS) \
$(FT_CFLAGS) \
"-msse4.1"
# DENSE driver sources (i.e., C files)
#
DENSE_DRV_SRC := $(DENSE_DIR)/ftdense.c \
$(DENSE_DIR)/ftdenserend.c
# DENSE driver headers
#
DENSE_DRV_H := $(DENSE_DRV_SRC:%c=%h) \
$(DENSE_DIR)/ftdenseerrs.h
# DENSE driver object(s)
#
# DENSE_DRV_OBJ_M is used during `multi' builds.
# DENSE_DRV_OBJ_S is used during `single' builds.
#
DENSE_DRV_OBJ_M := $(DENSE_DRV_SRC:$(DENSE_DIR)/%.c=$(OBJ_DIR)/%.$O)
DENSE_DRV_OBJ_S := $(OBJ_DIR)/dense.$O
# DENSE driver source file for single build
#
DENSE_DRV_SRC_S := $(DENSE_DIR)/dense.c
# DENSE driver - single object
#
$(DENSE_DRV_OBJ_S): $(DENSE_DRV_SRC_S) $(DENSE_DRV_SRC) \
$(FREETYPE_H) $(DENSE_DRV_H)
$(DENSE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(DENSE_DRV_SRC_S))
# DENSE driver - multiple objects
#
$(OBJ_DIR)/%.$O: $(DENSE_DIR)/%.c $(FREETYPE_H) $(DENSE_DRV_H)
$(DENSE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
# update main driver object lists
#
DRV_OBJS_S += $(DENSE_DRV_OBJ_S)
DRV_OBJS_M += $(DENSE_DRV_OBJ_M)
# EOF