Compare commits

...

22 Commits

Author SHA1 Message Date
Anurag Thakur
b1f9f98e45 [dense] Add support for rendering prelines
* src/dense/ftdense.c: Add dense_render_line2 function, that takes
a PreLine as argument.

FT_Outline_Decompose call in dense_render_glyph replaced by a loop
that renders PreLines

* src/dense/ftdenserend.c: Add support for shifting PreLines as
per target bitmap
2023-10-10 03:41:29 +05:30
Anurag Thakur
c1804c48a9 [dense] Add support for preloading in ft_open_face_internal
* src/base/ftobjs.c: Add code for loading glyph data into
face->glyph_aray after ft_open_face_internal has succeeded
2023-10-10 03:39:47 +05:30
Anurag Thakur
2254ce1906 [dense] Add code for curve flattening at load time
src/base/ftobjs.c: Add Lerp, conic_to2, ft_decompose_outline functions
2023-10-10 03:38:02 +05:30
Anurag Thakur
b2f570a2bb [dense] Implement FT_New_Face2 and fix glyph loading
* include/freetype/freetype.h: Add filed "size" to FT_Open_Args

* src/base/ftobjs.c: Use slot from face's glyph_array in FT_Load_Glyph
Implement FT_New_Face2
2023-10-10 03:35:20 +05:30
Anurag Thakur
e7c4fb9d13 [dense] Add FT_Refresh_Glyph
* include/freetype/freetype.h: Declare FT_Refresh_Glyph

* src/base/ftobjs.c: Implement FT_Refresh_Glyph
2023-10-10 03:31:03 +05:30
Anurag Thakur
d074c39cd9 [dense] Modified FT_FaceRec, FT_GlyphSlotRec and FT_Raster_Params
* include/freetype/freetype.h: Add glyph_array filed to FT_FaceRec,
prelines, prel_shifted fileds to GlyphSlotRec

* include/freetype/ftimage.h: Add prelines filed to FT_raster_Params
2023-10-10 03:28:13 +05:30
Anurag Thakur
c33e0b82de [dense] Add FT_PreLine struct
* include/freetype/freetype.h: Add FT_PreLineRec struct and its handle FT_PreLine
2023-10-10 03:26:28 +05:30
Anurag Thakur
45de1dba73 [dense] Declare FT_New_Face2
* include/freetype/freetype.h: Add FT_New_Face2 function to be used
for preloading optimization
2023-10-10 03:24:09 +05:30
Anurag Thakur
3b3c46629e [dense] Add ARM NEON support and improve SSE perf
* src/dense/ftdense.c: Add FT_NEON flag, implement ARM NEON support
in dense_render_glyph, improve SSE performance

* src/dense/rules.mk: Replacse -msse4.1 with -march=native
2023-10-10 03:20:48 +05:30
Anurag Thakur
1bf65eff60 [dense] Add compilation fixes for meson
* builds/meson/parse_modules_cfg.py: Add dense module

* meson.build: Add SSE flags to ft2_defines, -lm to link_args

* src/dense/ftdense.c: Fixes for compilation errors
2023-10-10 03:17:34 +05:30
Anurag Thakur
cf779f5fbf [dense] Add -msse4.1 to compile with CMake
* CMakeLists.txt: Add -msse4.1 to ${CMAKE_C_FLAGS}
2023-10-10 03:15:13 +05:30
Anurag Thakur
724e81ef5b [dense] Add optimization for division
* src/dense/ftdense.c: FT_UDIV, FT_UDIVPREP macros taken from smooth
rasterizer, help optimize fixed-point division
2023-10-10 01:46:43 +05:30
Anurag Thakur
668bc29ff0 [dense] Add optimization for vertical lines
* src/dense/ftdense.c: Optimize line drawing when a vertical line is encountered
2023-10-10 01:46:43 +05:30
Anurag Thakur
bca7bda1e7 [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
2023-10-10 01:46:43 +05:30
Anurag Thakur
3e56c9bf62 [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
2023-10-10 01:46:37 +05:30
Anurag Thakur
70d6a8ef1a [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
2023-08-09 01:32:15 +05:30
Anurag Thakur
2504e2de84 [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
2023-08-09 01:32:15 +05:30
Anurag Thakur
5e681678f6 [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
2023-08-09 01:32:15 +05:30
Anurag Thakur
f2ff1dc37e [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
2023-08-09 01:32:15 +05:30
Anurag Thakur
abce0cab72 [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)
2023-08-09 01:32:15 +05:30
Anurag Thakur
f681099918 [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
2023-08-09 01:32:15 +05:30
Anurag Thakur
a78906fb4e [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.
2023-08-09 01:32:15 +05:30
16 changed files with 1688 additions and 2 deletions

View File

@ -247,6 +247,8 @@ if (BUILD_FRAMEWORK)
endif ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1")
# Find dependencies
include(FindPkgConfig)
@ -405,6 +407,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

@ -87,6 +87,7 @@ def generate_ftmodule(lists):
names = {
"raster": ("ft_raster1",),
"smooth": ("ft_smooth",),
"dense": ("ft_dense",),
"svg": ("ft_svg",),
"sdf": ("ft_sdf", "ft_bitmap_sdf"),
}.get(module)

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

@ -1276,6 +1276,7 @@ FT_BEGIN_HEADER
FT_ListRec sizes_list;
FT_Generic autohint; /* face-specific auto-hinter data */
FT_GlyphSlot* glyph_array;
void* extensions; /* unused */
FT_Face_Internal internal;
@ -1283,6 +1284,44 @@ FT_BEGIN_HEADER
} FT_FaceRec;
/**************************************************************************
*
* @type:
* FT_PreLine
*
* @description:
* A handle to FT_PreLineRec_ containing coordinates of start and end
* points for a line.
*
*/
typedef struct FT_PreLineRec_* FT_PreLine;
/**************************************************************************
*
* @struct:
* FT_PreLineRec
*
* @description:
* Linkedlist containing lines to be drawn for a glyph.
*
* @fields:
* x1, y1 ::
* Coordinates of line start point.
*
* y1, y2 ::
* Coordinates of line end point.
*
* next ::
* The next PreLine for current glyph
*
*/
typedef struct FT_PreLineRec_
{
int x1, x2, y1, y2;
FT_PreLine next;
} FT_PreLineRec;
/**************************************************************************
*
* @enum:
@ -2171,6 +2210,12 @@ FT_BEGIN_HEADER
* other ::
* Reserved.
*
* prelines ::
* Linkedlist containing lines to be drawn for the glyph
*
* prel_shifted ::
* If the points in preline have been adjustted according to target bitmap
*
* lsb_delta ::
* The difference between hinted and unhinted left side bearing while
* auto-hinting is active. Zero otherwise.
@ -2288,6 +2333,8 @@ FT_BEGIN_HEADER
FT_Pos rsb_delta;
void* other;
FT_PreLine prelines;
int prel_shifted;
FT_Slot_Internal internal;
@ -2487,6 +2534,10 @@ FT_BEGIN_HEADER
* params ::
* Extra parameters passed to the font driver when opening a new face.
*
* size ::
* Size at which the glyphs will be rendered. Use same value as
* @FT_Set_Pixel_Sizes
*
* @note:
* The stream type is determined by the contents of `flags`:
*
@ -2524,6 +2575,7 @@ FT_BEGIN_HEADER
FT_Module driver;
FT_Int num_params;
FT_Parameter* params;
FT_UInt size;
} FT_Open_Args;
@ -2573,6 +2625,54 @@ FT_BEGIN_HEADER
FT_Face *aface );
/**************************************************************************
*
* @function:
* FT_New_Face2
*
* @description:
* Call @FT_Open_Face to open a font by its pathname with given flags.
*
* @inout:
* library ::
* A handle to the library resource.
*
* @input:
* pathname ::
* A path to the font file.
*
* face_index ::
* See @FT_Open_Face for a detailed description of this parameter.
*
* size ::
* Size at which glyphs will be rendered, Use the same value as @FT_Set_Pixel_Sizes
*
* @output:
* aface ::
* A handle to a new face object. If `face_index` is greater than or
* equal to zero, it must be non-`NULL`.
*
* @return:
* FreeType error code. 0~means success.
*
* @note:
* The `pathname` string should be recognizable as such by a standard
* `fopen` call on your system; in particular, this means that `pathname`
* must not contain null bytes. If that is not sufficient to address all
* file name possibilities (for example, to handle wide character file
* names on Windows in UTF-16 encoding) you might use @FT_Open_Face to
* pass a memory array or a stream object instead.
*
* Use @FT_Done_Face to destroy the created @FT_Face object (along with
* its slot and sizes).
*/
FT_EXPORT( FT_Error )
FT_New_Face2( FT_Library library,
const char* filepathname,
FT_Long face_index,
FT_Face *aface,
FT_UInt size);
/**************************************************************************
*
* @function:
@ -3228,6 +3328,31 @@ FT_BEGIN_HEADER
FT_UInt glyph_index,
FT_Int32 load_flags );
/**************************************************************************
*
* @function:
* FT_Refresh_Glyph
*
* @description:
* Prepare the glyph at glyph_index for rendering. Resets the glyph
* if it has already been rendered
*
* @inout:
* face ::
* A handle to the target face object where the glyph is loaded.
*
* @input:
* glyph_index ::
* The index of the glyph in the font file.
*
* @return:
* FreeType error code. 0~means success.
*
*/
FT_EXPORT( FT_Error )
FT_Refresh_Glyph( FT_Face face,
FT_UInt glyph_index);
/**************************************************************************
*

View File

@ -1030,6 +1030,9 @@ FT_BEGIN_HEADER
* An optional span clipping box expressed in _integer_ pixels
* (not in 26.6 fixed-point units).
*
* prelines ::
* Pointer of type FT_PreLine, containing line data for a glyph
*
* @note:
* The @FT_RASTER_FLAG_AA bit flag must be set in the `flags` to
* generate an anti-aliased glyph bitmap, otherwise a monochrome bitmap
@ -1059,6 +1062,7 @@ FT_BEGIN_HEADER
FT_Raster_BitSet_Func bit_set; /* unused */
void* user;
FT_BBox clip_box;
void* prelines;
} FT_Raster_Params;

View File

@ -395,6 +395,13 @@ if use_unix_ftsystem_c
endif
if cc.get_id() == 'msvc'
ft2_defines += ['/arch:AVX']
else
ft2_defines += ['-msse4.1']
endif
ft2_lib = library('freetype',
sources: ft2_sources + [ftmodule_h],
c_args: ft2_defines,
@ -403,7 +410,7 @@ ft2_lib = library('freetype',
dependencies: ft2_deps,
install: true,
version: ft2_so_version,
link_args: common_ldflags,
link_args: common_ldflags + ['-lm'],
)

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

View File

@ -42,6 +42,7 @@
#include <freetype/internal/services/svkern.h>
#include <freetype/internal/services/svtteng.h>
#include <math.h>
#include <freetype/ftdriver.h>
#ifdef FT_CONFIG_OPTION_MAC_FONTS
@ -893,6 +894,14 @@
/* documentation is in freetype.h */
FT_EXPORT_DEF( FT_Error )
FT_Refresh_Glyph( FT_Face face,
FT_UInt glyph_index)
{
ft_glyphslot_free_bitmap( face->glyph_array[glyph_index] );
face->glyph_array[glyph_index]->format = FT_GLYPH_FORMAT_OUTLINE;
}
FT_EXPORT_DEF( FT_Error )
FT_Load_Glyph( FT_Face face,
@ -914,7 +923,7 @@
/* The validity test for `glyph_index' is performed by the */
/* font drivers. */
slot = face->glyph;
slot = face->glyph_array[glyph_index];
ft_glyphslot_clear( slot );
driver = face->driver;
@ -1616,12 +1625,34 @@
return FT_THROW( Invalid_Argument );
args.flags = FT_OPEN_PATHNAME;
args.size = 0;
args.pathname = (char*)pathname;
args.stream = NULL;
return ft_open_face_internal( library, &args, face_index, aface, 1 );
}
FT_EXPORT_DEF( FT_Error )
FT_New_Face2( FT_Library library,
const char* pathname,
FT_Long face_index,
FT_Face *aface,
FT_UInt size)
{
FT_Open_Args args;
/* test for valid `library' and `aface' delayed to `FT_Open_Face' */
if ( !pathname )
return FT_THROW( Invalid_Argument );
args.flags = FT_OPEN_PATHNAME;
args.size = size;
args.pathname = (char*)pathname;
args.stream = NULL;
return ft_open_face_internal( library, &args, face_index, aface, 1 );
}
#endif
@ -2519,6 +2550,306 @@
}
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;
}
int conic_to2(FT_GlyphSlot* slot, FT_Vector *control, FT_Vector *from, FT_Vector *to, FT_PreLine *ptr)
{
/*
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 = { from->x , from->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 )
{
FT_PreLine pl3 = malloc(sizeof(FT_PreLineRec));
pl3->x1 = (*ptr)->x2;
pl3->y1 = (*ptr)->y2;
pl3->x2 = aP2.x;
pl3->y2 = aP2.y;
pl3->next = NULL;
(*ptr)->next = pl3;
*ptr = (*ptr)->next;
return 0;
}
/*
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 ) );
FT_PreLine pl4 = malloc(sizeof(FT_PreLineRec));
pl4->x1 = (*ptr)->x2;
pl4->y1 = (*ptr)->y2;
pl4->x2 = next.x;
pl4->y2 = next.y;
pl4->next = NULL;
(*ptr)->next = pl4;
*ptr = (*ptr)->next;
p = next;
}
FT_PreLine pl5 = malloc(sizeof(FT_PreLineRec));
pl5->x1 = (*ptr)->x2;
pl5->y1 = (*ptr)->y2;
pl5->x2 = aP2.x;
pl5->y2 = aP2.y;
pl5->next = NULL;
(*ptr)->next = pl5;
*ptr = (*ptr)->next;
return 0;
}
/**
* Convert the outline data of slot to prelines
*/
FT_Error ft_decompose_outline(FT_GlyphSlot* slot){
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
FT_Vector* point;
FT_Vector* limit;
char* tags;
FT_Error error;
FT_Int n; /* index of contour in outline */
FT_Int first; /* index of first point in contour */
FT_Int last; /* index of last point in contour */
FT_Int tag; /* current point's state */
FT_Int shift;
FT_Pos delta;
FT_Outline* outline = &(*slot)->outline;
if ( !outline )
return FT_THROW( Invalid_Outline );
last = -1;
FT_PreLine ptr = (*slot)->prelines;
for ( n = 0; n < outline->n_contours; n++ )
{
FT_TRACE5(( "ft_decompose_outline: Contour %d\n", n ));
first = last + 1;
last = outline->contours[n];
if ( last < first ){
FT_TRACE5(( "Invalid Outline"));
break;
}
limit = outline->points + last;
v_start = outline->points[first];
v_last = outline->points[last];
v_control = v_start;
point = outline->points + first;
tags = outline->tags + first;
tag = FT_CURVE_TAG( tags[0] );
/* A contour cannot start with a cubic control point! */
if ( tag == FT_CURVE_TAG_CUBIC )
{
FT_TRACE5(( "Invalid Outline"));
break;
}
/* check first point to determine origin */
if ( tag == FT_CURVE_TAG_CONIC )
{
/* first point is conic control. Yes, this happens. */
if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
{
/* start at last point if it is on the curve */
v_start = v_last;
limit--;
}
else
{
/* if both first and last points are conic, */
/* start at their middle and record its position */
/* for closure */
v_start.x = ( v_start.x + v_last.x ) / 2;
v_start.y = ( v_start.y + v_last.y ) / 2;
/* v_last = v_start; */
}
point--;
tags--;
}
FT_TRACE5(( " move to (%.2f, %.2f)\n",
(double)v_start.x / 64, (double)v_start.y / 64 ));
FT_PreLine pl = malloc(sizeof(FT_PreLineRec));
pl->x1 = v_start.x;
pl->y1 = v_start.y;
pl->x2 = v_start.x;
pl->y2 = v_start.y;
pl->next = NULL;
if ( ( *slot )->prelines == NULL )
{
ptr = ( *slot )->prelines = pl;
}
else
{
ptr->next = pl;
ptr = ptr->next;
}
while ( point < limit )
{
point++;
tags++;
tag = FT_CURVE_TAG( tags[0] );
switch ( tag )
{
case FT_CURVE_TAG_ON: /* emit a single line_to */
{
FT_Vector vec;
vec.x = point->x;
vec.y = point->y;
FT_TRACE5(( " line to (%.2f, %.2f)\n",
(double)vec.x / 64, (double)vec.y / 64 ));
FT_PreLine pl3 = malloc(sizeof(FT_PreLineRec));
pl3->x1 = ptr->x2;
pl3->y1 = ptr->y2;
pl3->x2 = vec.x;
pl3->y2 = vec.y;
pl3->next = NULL;
ptr->next = pl3;
ptr = ptr->next;
continue;
}
case FT_CURVE_TAG_CONIC: /* consume conic arcs */
v_control.x = point->x ;
v_control.y = point->y ;
Do_Conic:
if ( point < limit )
{
FT_Vector vec;
FT_Vector v_middle;
point++;
tags++;
tag = FT_CURVE_TAG( tags[0] );
vec.x = point->x;
vec.y = point->y;
if ( tag == FT_CURVE_TAG_ON )
{
FT_TRACE5(( " conic to (%.2f, %.2f)"
" with control (%.2f, %.2f)\n",
(double)vec.x / 64,
(double)vec.y / 64,
(double)v_control.x / 64,
(double)v_control.y / 64 ));
FT_Vector vex0 = {ptr->x2, ptr->y2};
error = conic_to2(slot, &v_control, &vex0,&vec , &ptr);
continue;
}
if ( tag != FT_CURVE_TAG_CONIC )
{
FT_TRACE5( ( "Invalid Outline" ) );
break;
}
v_middle.x = ( v_control.x + vec.x ) / 2;
v_middle.y = ( v_control.y + vec.y ) / 2;
FT_TRACE5(( " conic to (%.2f, %.2f)"
" with control (%.2f, %.2f)\n",
(double)v_middle.x / 64,
(double)v_middle.y / 64,
(double)v_control.x / 64,
(double)v_control.y / 64 ));
FT_Vector vex = {ptr->x2, ptr->y2};
error = conic_to2(slot, &v_control, &vex,&v_middle, &ptr);
v_control = vec;
goto Do_Conic;
}
FT_TRACE5(( " conic to (%.2f, %.2f)"
" with control (%.2f, %.2f)\n",
(double)v_start.x / 64,
(double)v_start.y / 64,
(double)v_control.x / 64,
(double)v_control.y / 64 ));
FT_Vector vex2 = {ptr->x2, ptr->y2};
error = conic_to2( slot, &v_control, &vex2, &v_start, &ptr );
}
}
/* close the contour with a line segment */
FT_TRACE5(( " line to (%.2f, %.2f)\n",
(double)v_start.x / 64, (double)v_start.y / 64 ));
FT_PreLine pl2 = malloc(sizeof(FT_PreLineRec));
pl2->x1 = ptr->x2;
pl2->y1 = ptr->y2;
pl2->x2 = v_start.x;
pl2->y2 = v_start.y;
pl2->next = NULL;
ptr->next = pl2;
ptr = ptr->next;
}
return 0;
}
static FT_Error
ft_open_face_internal( FT_Library library,
const FT_Open_Args* args,
@ -2748,6 +3079,33 @@
face->size = size;
}
if ( args->size > 0 )
{
face->glyph_array = (FT_GlyphSlot*)malloc(
face->driver->clazz->slot_object_size * face->num_glyphs );
error = FT_Set_Pixel_Sizes( face, 0, args->size );
for ( int gindex = 0; gindex < face->num_glyphs; gindex++ )
{
driver = face->driver;
FT_Driver_Class clazz = driver->clazz;
memory = driver->root.memory;
FT_ALLOC( face->glyph_array[gindex], clazz->slot_object_size );
face->glyph_array[gindex]->face = face;
face->glyph_array[gindex]->prel_shifted = 0;
face->glyph_array[gindex]->glyph_index = gindex;
ft_glyphslot_init( face->glyph_array[gindex] );
face->glyph_array[gindex]->next = NULL;
*face->glyph = *face->glyph_array[gindex];
FT_Load_Glyph( face, gindex, FT_LOAD_NO_HINTING );
ft_decompose_outline( &face->glyph_array[gindex] );
}
}
}
/* some checks */

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

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

@ -0,0 +1,741 @@
/** 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 defined(__ARM_NEON)
#define FT_NEON 1
#else
#define FT_NEON 0
#endif
#if FT_SSE4_1
#include <immintrin.h>
#elif FT_NEON
#include <arm_neon.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_line2( dense_worker* worker, FT_PreLine pl )
{
FT26D6 fx = UPSCALE(pl->x1)>>2;
FT26D6 fy = UPSCALE(pl->y1)>>2;
FT26D6 from_x = fx;
FT26D6 from_y = fy;
FT26D6 tx = UPSCALE(pl->x2)>>2;
FT26D6 ty = UPSCALE(pl->y2)>>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 = FT_MIN( (y + 1)<<6, to_y ) - FT_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;
}
}
}
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 = FT_MIN( (y + 1)<<6, to_y ) - FT_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_PreLine pl )
{
FT_Error error = 0;
while (pl != NULL)
{
dense_render_line2(worker, pl);
pl = pl->next;
}
// 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 nzero = _mm_castps_si128(_mm_set1_ps(-0.0));
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_slli_si128( x, 8 ) );
// add the prefix sum of previous 4 ints to all ints
x = _mm_add_epi32( x, offset );
// take absolute value
__m128i y = _mm_srli_epi32( _mm_abs_epi32( x) , 4 );
y = _mm_packus_epi16(_mm_packs_epi32(y, nzero), nzero);
_mm_storeu_si32(&dest[i], y);
// store the current prefix sum in offset
offset = _mm_shuffle_epi32(x,_MM_SHUFFLE( 3, 3, 3, 3 ) );
}
#elif FT_NEON
int32x4_t offset = vdupq_n_s32(0);
int32x4_t nzero = vreinterpretq_s32_f32(vdupq_n_f32(-0.0));
for (int i = 0; i < worker->m_h*worker->m_w; i += 4)
{
// load 4 floats from source
int32x4_t x = vld1q_s32( (int32_t*)&source[i] );
x = vaddq_s32( x, vreinterpretq_s32_s8(vextq_s8(vdupq_n_s8(0), vreinterpretq_s8_s32( x), 12) ));
x = vaddq_s32(x, vreinterpretq_s32_s8(vextq_s8(vdupq_n_s8(0), vreinterpretq_s8_s32(x), 8)));
// add the prefsum of previous 4 floats to all current floats
x = vaddq_s32( x, offset );
int32x4_t y = vshrq_n_s32( vabsq_s32( x) , 4 );
y = vreinterpretq_s32_s16(vcombine_s16(vqmovn_s32(y), vqmovn_s32(nzero)));
y = vreinterpretq_s32_u8(vcombine_u8(vqmovun_s16(vreinterpretq_s16_s32(y)), vqmovun_s16(vreinterpretq_s16_s32(nzero))));
vst1q_s32(&dest[i], y);
offset = vdupq_laneq_s32(x,3 );
}
#else
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 || FT_NEON */
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;
FT_PreLine pl = params->prelines;
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 + 3) & ~3;
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, pl );
}
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. */
FT20D12* 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 */

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

@ -0,0 +1,234 @@
/** 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 */
// ARM NEON crashes if memory is not aligned
if ( FT_ALLOC_MULT( bitmap->buffer, 1,bitmap->rows*bitmap->pitch + 16 ) )
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) && !slot->prel_shifted){
//FT_Outline_Translate( outline, x_shift, y_shift );
FT_PreLine pl = slot->prelines;
while (pl!=NULL)
{
pl->x1 += x_shift;
pl->y1 += y_shift;
pl->x2 += x_shift;
pl->y2 += y_shift;
pl = pl->next;
}
slot->prel_shifted = 1;
}
/* set up parameters */
params.target = bitmap;
params.source = outline;
params.prelines = slot->prelines;
/* 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) \
"-march=native"
# 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