Compare commits
3 Commits
master
...
1100-sdf-i
Author | SHA1 | Date | |
---|---|---|---|
|
ab950e18f4 | ||
|
b3d917d2f8 | ||
|
5f9bc4b859 |
@ -3409,6 +3409,45 @@ FT_BEGIN_HEADER
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* FreeType has two rasterizers for generating SDF, namely:
|
||||
*
|
||||
* 1. `sdf` - For generating SDF directly from glyph's outline.
|
||||
*
|
||||
* 2. `bsdf` - For generating SDF from rasterized bitmaps.
|
||||
*
|
||||
* Depending on the glyph type (i.e. outline or bitmap), one of the two
|
||||
* rasterizer is chosen at runtime and used for generating SDF. To
|
||||
* force use `bsdf` you can simply render the glyph using any of the
|
||||
* FreeType's other rendering modes (e.g. `FT_RENDER_MODE_NORMAL`) and
|
||||
* then re-render using `FT_RENDER_MODE_SDF`.
|
||||
*
|
||||
* Now, a few notes on the stability and point of failures for the SDF
|
||||
* renderers (specifically `sdf`):
|
||||
*
|
||||
* 1. The `sdf` rasterizer is sensitive to really small features (e.g.
|
||||
* sharp turns which are less than 1 pixel) and imperfections in the
|
||||
* glyph's outline. Having these in the outline can cause artifats
|
||||
* in the final output.
|
||||
*
|
||||
* 2. The `sdf` rasterizer has limited support for handling intersecting
|
||||
* contours and *cannot* handle self-intersecting contours whatsoever.
|
||||
* Self intersection happens when a single connected contour intersect
|
||||
* itself at some point and having these in your font will definately
|
||||
* pose a problem to the rasterizer and cause artifacts.
|
||||
*
|
||||
* 3. Generating SDF for really small glyphs may result in undesirable
|
||||
* output due to limited availability of pixel grid to store distance
|
||||
* information.
|
||||
*
|
||||
* 4. Since the output buffer is normalized, precision at smaller spread
|
||||
* will be greater than precision at larger spread values, because the
|
||||
* output range of [0 .. 255] will be mapped to a smaller sdf range.
|
||||
* A spread of 2 should be sufficient in most cases.
|
||||
*
|
||||
* Point (1) and (2) can be avoided by using `bsdf` and overall it is
|
||||
* more stable than the `sdf` rasterizer.
|
||||
*
|
||||
*/
|
||||
typedef enum FT_Render_Mode_
|
||||
{
|
||||
|
@ -738,6 +738,18 @@
|
||||
|
||||
contour = shape->contours;
|
||||
|
||||
/* If the control point coincide with any of the end point */
|
||||
/* then it's a line and should be treated as one to avoid */
|
||||
/* unnecessary complexity later in the algorithm. */
|
||||
if ( ( contour->last_pos.x == control_1->x &&
|
||||
contour->last_pos.y == control_1->y ) ||
|
||||
( control_1->x == to->x &&
|
||||
control_1->y == to->y ) )
|
||||
{
|
||||
sdf_line_to( to, user );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
FT_CALL( sdf_edge_new( memory, &edge ) );
|
||||
|
||||
edge->edge_type = SDF_EDGE_CONIC;
|
||||
@ -1137,9 +1149,10 @@
|
||||
FT_Int max_splits,
|
||||
SDF_Edge** out )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_26D6_Vec cpos[7];
|
||||
SDF_Edge* left,* right;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_26D6_Vec cpos[7];
|
||||
SDF_Edge* left,* right;
|
||||
const FT_26D6 threshold = ONE_PIXEL / 4;
|
||||
|
||||
|
||||
if ( !memory || !out )
|
||||
@ -1148,11 +1161,24 @@
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* split the conic */
|
||||
/* split the cubic */
|
||||
cpos[0] = control_points[0];
|
||||
cpos[1] = control_points[1];
|
||||
cpos[2] = control_points[2];
|
||||
cpos[3] = control_points[3];
|
||||
|
||||
/* If the segment is flat enough, we won't get any benifit by */
|
||||
/* splitting it further, so we can just stop splitting. Here, */
|
||||
/* we check the deviation of the bezier and stop if it is */
|
||||
/* lower than a pre-defined `threhold` value. */
|
||||
if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold &&
|
||||
FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold &&
|
||||
FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold &&
|
||||
FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold )
|
||||
{
|
||||
split_cubic( cpos );
|
||||
goto Append;
|
||||
}
|
||||
|
||||
split_cubic( cpos );
|
||||
|
||||
@ -1250,13 +1276,31 @@
|
||||
/* Subdivide the curve and add it to the list. */
|
||||
{
|
||||
FT_26D6_Vec ctrls[3];
|
||||
FT_26D6 dx, dy;
|
||||
FT_UInt num_splits;
|
||||
|
||||
|
||||
ctrls[0] = edge->start_pos;
|
||||
ctrls[1] = edge->control_a;
|
||||
ctrls[2] = edge->end_pos;
|
||||
|
||||
error = split_sdf_conic( memory, ctrls, 32, &new_edges );
|
||||
dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x );
|
||||
dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y );
|
||||
if ( dx < dy )
|
||||
dx = dy;
|
||||
|
||||
/* Here we calculate the number of necessary bisections. Each */
|
||||
/* bisection reduces the deviation by exactly 4-fold, hence */
|
||||
/* we bisect the bezier until the deviation becomes less than */
|
||||
/* 1/8th of a pixel. For more details check `ftgrays.c`. */
|
||||
num_splits = 1;
|
||||
while ( dx > ONE_PIXEL / 8 )
|
||||
{
|
||||
dx >>= 2;
|
||||
num_splits <<= 1;
|
||||
}
|
||||
|
||||
error = split_sdf_conic( memory, ctrls, num_splits, &new_edges );
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3286,6 +3330,7 @@
|
||||
FT_26D6_Vec grid_point = zero_vector;
|
||||
SDF_Signed_Distance dist = max_sdf;
|
||||
FT_UInt index = 0;
|
||||
FT_16D16 diff = 0;
|
||||
|
||||
|
||||
if ( x < 0 || x >= width )
|
||||
@ -3313,7 +3358,7 @@
|
||||
if ( dist.distance > sp_sq )
|
||||
continue;
|
||||
|
||||
/* square_root the values and fit in a 6.10 fixed-point */
|
||||
/* square_root the values if required */
|
||||
if ( USE_SQUARED_DISTANCES )
|
||||
dist.distance = square_root( dist.distance );
|
||||
|
||||
@ -3325,11 +3370,15 @@
|
||||
/* check whether the pixel is set or not */
|
||||
if ( dists[index].sign == 0 )
|
||||
dists[index] = dist;
|
||||
else if ( dists[index].distance > dist.distance )
|
||||
dists[index] = dist;
|
||||
else if ( FT_ABS( dists[index].distance - dist.distance )
|
||||
< CORNER_CHECK_EPSILON )
|
||||
dists[index] = resolve_corner( dists[index], dist );
|
||||
else
|
||||
{
|
||||
diff = FT_ABS( dists[index].distance - dist.distance );
|
||||
|
||||
if ( diff <= CORNER_CHECK_EPSILON )
|
||||
dists[index] = resolve_corner( dists[index], dist );
|
||||
else if ( dists[index].distance > dist.distance )
|
||||
dists[index] = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,8 @@ FT_BEGIN_HEADER
|
||||
#define MIN_SPREAD 2
|
||||
/* maximum spread supported by the renderer */
|
||||
#define MAX_SPREAD 32
|
||||
/* pixel size in 26.6 */
|
||||
#define ONE_PIXEL ( 1 << 6 )
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user