2018-06-03 09:01:17 +02:00
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* afhints.c
|
|
|
|
*
|
|
|
|
* Auto-fitter hinting routines (body).
|
|
|
|
*
|
2022-01-11 10:54:10 +01:00
|
|
|
* Copyright (C) 2003-2022 by
|
2018-06-03 09:01:17 +02:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
2005-03-03 18:09:08 +01:00
|
|
|
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
#include "afhints.h"
|
2005-03-23 17:45:24 +01:00
|
|
|
#include "aferrors.h"
|
2020-06-08 13:31:55 +02:00
|
|
|
#include <freetype/internal/ftcalc.h>
|
|
|
|
#include <freetype/internal/ftdebug.h>
|
2012-07-06 19:38:44 +02:00
|
|
|
|
|
|
|
|
2018-06-03 09:01:17 +02:00
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-07-06 19:38:44 +02:00
|
|
|
#undef FT_COMPONENT
|
2018-08-15 18:13:17 +02:00
|
|
|
#define FT_COMPONENT afhints
|
2005-03-01 16:48:29 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2021-06-02 19:07:56 +02:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_sort_pos( FT_UInt count,
|
|
|
|
FT_Pos* table )
|
|
|
|
{
|
|
|
|
FT_UInt i, j;
|
|
|
|
FT_Pos swap;
|
|
|
|
|
|
|
|
|
|
|
|
for ( i = 1; i < count; i++ )
|
|
|
|
{
|
|
|
|
for ( j = i; j > 0; j-- )
|
|
|
|
{
|
|
|
|
if ( table[j] >= table[j - 1] )
|
|
|
|
break;
|
|
|
|
|
|
|
|
swap = table[j];
|
|
|
|
table[j] = table[j - 1];
|
|
|
|
table[j - 1] = swap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_sort_and_quantize_widths( FT_UInt* count,
|
|
|
|
AF_Width table,
|
|
|
|
FT_Pos threshold )
|
|
|
|
{
|
|
|
|
FT_UInt i, j;
|
|
|
|
FT_UInt cur_idx;
|
|
|
|
FT_Pos cur_val;
|
|
|
|
FT_Pos sum;
|
|
|
|
AF_WidthRec swap;
|
|
|
|
|
|
|
|
|
|
|
|
if ( *count == 1 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* sort */
|
|
|
|
for ( i = 1; i < *count; i++ )
|
|
|
|
{
|
|
|
|
for ( j = i; j > 0; j-- )
|
|
|
|
{
|
|
|
|
if ( table[j].org >= table[j - 1].org )
|
|
|
|
break;
|
|
|
|
|
|
|
|
swap = table[j];
|
|
|
|
table[j] = table[j - 1];
|
|
|
|
table[j - 1] = swap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_idx = 0;
|
|
|
|
cur_val = table[cur_idx].org;
|
|
|
|
|
|
|
|
/* compute and use mean values for clusters not larger than */
|
|
|
|
/* `threshold'; this is very primitive and might not yield */
|
|
|
|
/* the best result, but normally, using reference character */
|
|
|
|
/* `o', `*count' is 2, so the code below is fully sufficient */
|
|
|
|
for ( i = 1; i < *count; i++ )
|
|
|
|
{
|
|
|
|
if ( table[i].org - cur_val > threshold ||
|
|
|
|
i == *count - 1 )
|
|
|
|
{
|
|
|
|
sum = 0;
|
|
|
|
|
|
|
|
/* fix loop for end of array */
|
|
|
|
if ( table[i].org - cur_val <= threshold &&
|
|
|
|
i == *count - 1 )
|
|
|
|
i++;
|
|
|
|
|
|
|
|
for ( j = cur_idx; j < i; j++ )
|
|
|
|
{
|
|
|
|
sum += table[j].org;
|
|
|
|
table[j].org = 0;
|
|
|
|
}
|
|
|
|
table[cur_idx].org = sum / (FT_Pos)j;
|
|
|
|
|
|
|
|
if ( i < *count - 1 )
|
|
|
|
{
|
|
|
|
cur_idx = i + 1;
|
|
|
|
cur_val = table[cur_idx].org;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_idx = 1;
|
|
|
|
|
|
|
|
/* compress array to remove zero values */
|
|
|
|
for ( i = 1; i < *count; i++ )
|
|
|
|
{
|
|
|
|
if ( table[i].org )
|
|
|
|
table[cur_idx++] = table[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
*count = cur_idx;
|
|
|
|
}
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Get new segment for given axis. */
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
|
|
|
af_axis_hints_new_segment( AF_AxisHints axis,
|
|
|
|
FT_Memory memory,
|
|
|
|
AF_Segment *asegment )
|
|
|
|
{
|
2013-03-14 11:21:17 +01:00
|
|
|
FT_Error error = FT_Err_Ok;
|
2005-03-01 16:48:29 +01:00
|
|
|
AF_Segment segment = NULL;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
|
|
|
|
{
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !axis->segments )
|
2015-01-14 19:36:02 +01:00
|
|
|
{
|
|
|
|
axis->segments = axis->embedded.segments;
|
|
|
|
axis->max_segments = AF_SEGMENTS_EMBEDDED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( axis->num_segments >= axis->max_segments )
|
2005-03-01 16:48:29 +01:00
|
|
|
{
|
|
|
|
FT_Int old_max = axis->max_segments;
|
|
|
|
FT_Int new_max = old_max;
|
2009-07-31 17:32:08 +02:00
|
|
|
FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
if ( old_max >= big_max )
|
|
|
|
{
|
2013-03-14 10:27:35 +01:00
|
|
|
error = FT_THROW( Out_Of_Memory );
|
2005-03-01 16:48:29 +01:00
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2005-04-04 00:09:41 +02:00
|
|
|
new_max += ( new_max >> 2 ) + 4;
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( new_max < old_max || new_max > big_max )
|
|
|
|
new_max = big_max;
|
|
|
|
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->segments == axis->embedded.segments )
|
|
|
|
{
|
|
|
|
if ( FT_NEW_ARRAY( axis->segments, new_max ) )
|
|
|
|
goto Exit;
|
|
|
|
ft_memcpy( axis->segments, axis->embedded.segments,
|
|
|
|
sizeof ( axis->embedded.segments ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
|
|
|
|
goto Exit;
|
|
|
|
}
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
axis->max_segments = new_max;
|
|
|
|
}
|
|
|
|
|
|
|
|
segment = axis->segments + axis->num_segments++;
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
*asegment = segment;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2014-09-22 06:42:24 +02:00
|
|
|
/* Get new edge for given axis, direction, and position, */
|
|
|
|
/* without initializing the edge itself. */
|
2011-02-16 21:59:44 +01:00
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
FT_LOCAL( FT_Error )
|
2005-03-01 16:48:29 +01:00
|
|
|
af_axis_hints_new_edge( AF_AxisHints axis,
|
|
|
|
FT_Int fpos,
|
2007-06-11 07:37:35 +02:00
|
|
|
AF_Direction dir,
|
2015-12-25 08:05:30 +01:00
|
|
|
FT_Bool top_to_bottom_hinting,
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Memory memory,
|
2012-07-06 19:38:44 +02:00
|
|
|
AF_Edge *anedge )
|
2005-03-01 16:48:29 +01:00
|
|
|
{
|
2013-03-14 11:21:17 +01:00
|
|
|
FT_Error error = FT_Err_Ok;
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_Edge edge = NULL;
|
|
|
|
AF_Edge edges;
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->num_edges < AF_EDGES_EMBEDDED )
|
|
|
|
{
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !axis->edges )
|
2015-01-14 19:36:02 +01:00
|
|
|
{
|
|
|
|
axis->edges = axis->embedded.edges;
|
|
|
|
axis->max_edges = AF_EDGES_EMBEDDED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( axis->num_edges >= axis->max_edges )
|
2005-03-01 16:48:29 +01:00
|
|
|
{
|
|
|
|
FT_Int old_max = axis->max_edges;
|
|
|
|
FT_Int new_max = old_max;
|
2009-07-31 17:32:08 +02:00
|
|
|
FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
if ( old_max >= big_max )
|
|
|
|
{
|
2013-03-14 10:27:35 +01:00
|
|
|
error = FT_THROW( Out_Of_Memory );
|
2005-03-01 16:48:29 +01:00
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2005-04-04 00:09:41 +02:00
|
|
|
new_max += ( new_max >> 2 ) + 4;
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( new_max < old_max || new_max > big_max )
|
|
|
|
new_max = big_max;
|
|
|
|
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->edges == axis->embedded.edges )
|
|
|
|
{
|
|
|
|
if ( FT_NEW_ARRAY( axis->edges, new_max ) )
|
|
|
|
goto Exit;
|
|
|
|
ft_memcpy( axis->edges, axis->embedded.edges,
|
|
|
|
sizeof ( axis->embedded.edges ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
|
|
|
|
goto Exit;
|
|
|
|
}
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
axis->max_edges = new_max;
|
|
|
|
}
|
|
|
|
|
|
|
|
edges = axis->edges;
|
|
|
|
edge = edges + axis->num_edges;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
while ( edge > edges )
|
2005-03-01 16:48:29 +01:00
|
|
|
{
|
2015-12-25 08:05:30 +01:00
|
|
|
if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos )
|
|
|
|
: ( edge[-1].fpos < fpos ) )
|
2007-06-11 07:37:35 +02:00
|
|
|
break;
|
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
/* we want the edge with same position and minor direction */
|
|
|
|
/* to appear before those in the major one in the list */
|
|
|
|
if ( edge[-1].fpos == fpos && dir == axis->major_dir )
|
2007-06-11 07:37:35 +02:00
|
|
|
break;
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
edge[0] = edge[-1];
|
|
|
|
edge--;
|
|
|
|
}
|
|
|
|
|
|
|
|
axis->num_edges++;
|
|
|
|
|
|
|
|
Exit:
|
2012-07-06 19:38:44 +02:00
|
|
|
*anedge = edge;
|
2005-03-01 16:48:29 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-18 19:05:28 +02:00
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2009-01-13 18:34:48 +01:00
|
|
|
#include FT_CONFIG_STANDARD_LIBRARY_H
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
/* The dump functions are used in the `ftgrid' demo program, too. */
|
|
|
|
#define AF_DUMP( varformat ) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
if ( to_stdout ) \
|
|
|
|
printf varformat; \
|
|
|
|
else \
|
|
|
|
FT_TRACE7( varformat ); \
|
|
|
|
} while ( 0 )
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
static const char*
|
|
|
|
af_dir_str( AF_Direction dir )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
const char* result;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
switch ( dir )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
case AF_DIR_UP:
|
|
|
|
result = "up";
|
|
|
|
break;
|
|
|
|
case AF_DIR_DOWN:
|
|
|
|
result = "down";
|
|
|
|
break;
|
|
|
|
case AF_DIR_LEFT:
|
|
|
|
result = "left";
|
|
|
|
break;
|
|
|
|
case AF_DIR_RIGHT:
|
|
|
|
result = "right";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = "none";
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2014-12-03 19:30:44 +01:00
|
|
|
#define AF_INDEX_NUM( ptr, base ) (int)( (ptr) ? ( (ptr) - (base) ) : -1 )
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-10-25 10:59:59 +01:00
|
|
|
static char*
|
|
|
|
af_print_idx( char* p,
|
|
|
|
int idx )
|
|
|
|
{
|
|
|
|
if ( idx == -1 )
|
|
|
|
{
|
|
|
|
p[0] = '-';
|
|
|
|
p[1] = '-';
|
|
|
|
p[2] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ft_sprintf( p, "%d", idx );
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
af_get_segment_index( AF_GlyphHints hints,
|
|
|
|
int point_idx,
|
|
|
|
int dimension )
|
|
|
|
{
|
|
|
|
AF_AxisHints axis = &hints->axis[dimension];
|
|
|
|
AF_Point point = hints->points + point_idx;
|
|
|
|
AF_Segment segments = axis->segments;
|
|
|
|
AF_Segment limit = segments + axis->num_segments;
|
|
|
|
AF_Segment segment;
|
|
|
|
|
|
|
|
|
|
|
|
for ( segment = segments; segment < limit; segment++ )
|
|
|
|
{
|
|
|
|
if ( segment->first <= segment->last )
|
|
|
|
{
|
|
|
|
if ( point >= segment->first && point <= segment->last )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-15 13:06:48 +01:00
|
|
|
AF_Point p = segment->first;
|
|
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if ( point == p )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
if ( p == segment->last )
|
|
|
|
break;
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
}
|
2015-10-25 10:59:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-15 13:06:48 +01:00
|
|
|
Exit:
|
2015-10-25 10:59:59 +01:00
|
|
|
if ( segment == limit )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return (int)( segment - segments );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
af_get_edge_index( AF_GlyphHints hints,
|
|
|
|
int segment_idx,
|
|
|
|
int dimension )
|
|
|
|
{
|
|
|
|
AF_AxisHints axis = &hints->axis[dimension];
|
|
|
|
AF_Edge edges = axis->edges;
|
|
|
|
AF_Segment segment = axis->segments + segment_idx;
|
|
|
|
|
|
|
|
|
|
|
|
return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-30 09:56:09 +02:00
|
|
|
static int
|
|
|
|
af_get_strong_edge_index( AF_GlyphHints hints,
|
|
|
|
AF_Edge* strong_edges,
|
|
|
|
int dimension )
|
|
|
|
{
|
|
|
|
AF_AxisHints axis = &hints->axis[dimension];
|
|
|
|
AF_Edge edges = axis->edges;
|
|
|
|
|
|
|
|
|
|
|
|
return AF_INDEX_NUM( strong_edges[dimension], edges );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
void
|
2013-11-27 10:10:16 +01:00
|
|
|
af_glyph_hints_dump_points( AF_GlyphHints hints,
|
|
|
|
FT_Bool to_stdout )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2016-01-30 07:44:30 +01:00
|
|
|
AF_Point points = hints->points;
|
|
|
|
AF_Point limit = points + hints->num_points;
|
|
|
|
AF_Point* contour = hints->contours;
|
|
|
|
AF_Point* climit = contour + hints->num_contours;
|
|
|
|
AF_Point point;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2015-04-01 15:55:41 +02:00
|
|
|
AF_DUMP(( "Table of points:\n" ));
|
|
|
|
|
|
|
|
if ( hints->num_points )
|
2017-10-12 00:13:51 +02:00
|
|
|
{
|
2016-03-20 22:20:32 +01:00
|
|
|
AF_DUMP(( " index hedge hseg vedge vseg flags "
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */
|
2018-08-30 09:56:09 +02:00
|
|
|
" xorg yorg xscale yscale xfit yfit "
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
|
2018-08-30 09:56:09 +02:00
|
|
|
" hbef haft vbef vaft" ));
|
|
|
|
/* " XXXXX XXXXX XXXXX XXXXX" */
|
2017-10-12 00:13:51 +02:00
|
|
|
}
|
2015-04-01 15:55:41 +02:00
|
|
|
else
|
|
|
|
AF_DUMP(( " (none)\n" ));
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( point = points; point < limit; point++ )
|
2015-10-25 10:59:59 +01:00
|
|
|
{
|
|
|
|
int point_idx = AF_INDEX_NUM( point, points );
|
|
|
|
int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
|
|
|
|
int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
|
|
|
|
|
|
|
|
char buf1[16], buf2[16], buf3[16], buf4[16];
|
2018-08-30 09:56:09 +02:00
|
|
|
char buf5[16], buf6[16], buf7[16], buf8[16];
|
2015-10-25 10:59:59 +01:00
|
|
|
|
|
|
|
|
2016-01-30 07:44:30 +01:00
|
|
|
/* insert extra newline at the beginning of a contour */
|
|
|
|
if ( contour < climit && *contour == point )
|
|
|
|
{
|
|
|
|
AF_DUMP(( "\n" ));
|
|
|
|
contour++;
|
|
|
|
}
|
|
|
|
|
2016-03-20 22:20:32 +01:00
|
|
|
AF_DUMP(( " %5d %5s %5s %5s %5s %s"
|
2018-08-30 09:56:09 +02:00
|
|
|
" %5d %5d %7.2f %7.2f %7.2f %7.2f"
|
|
|
|
" %5s %5s %5s %5s\n",
|
2015-10-25 10:59:59 +01:00
|
|
|
point_idx,
|
|
|
|
af_print_idx( buf1,
|
|
|
|
af_get_edge_index( hints, segment_idx_1, 1 ) ),
|
|
|
|
af_print_idx( buf2, segment_idx_1 ),
|
|
|
|
af_print_idx( buf3,
|
|
|
|
af_get_edge_index( hints, segment_idx_0, 0 ) ),
|
|
|
|
af_print_idx( buf4, segment_idx_0 ),
|
2016-03-20 22:20:32 +01:00
|
|
|
( point->flags & AF_FLAG_NEAR )
|
|
|
|
? " near "
|
|
|
|
: ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
|
|
|
|
? " weak "
|
|
|
|
: "strong",
|
2015-10-25 10:59:59 +01:00
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
point->fx,
|
|
|
|
point->fy,
|
|
|
|
point->ox / 64.0,
|
|
|
|
point->oy / 64.0,
|
|
|
|
point->x / 64.0,
|
2018-08-30 09:56:09 +02:00
|
|
|
point->y / 64.0,
|
|
|
|
|
|
|
|
af_print_idx( buf5, af_get_strong_edge_index( hints,
|
|
|
|
point->before,
|
|
|
|
1 ) ),
|
|
|
|
af_print_idx( buf6, af_get_strong_edge_index( hints,
|
|
|
|
point->after,
|
|
|
|
1 ) ),
|
|
|
|
af_print_idx( buf7, af_get_strong_edge_index( hints,
|
|
|
|
point->before,
|
|
|
|
0 ) ),
|
|
|
|
af_print_idx( buf8, af_get_strong_edge_index( hints,
|
|
|
|
point->after,
|
|
|
|
0 ) ) ));
|
2015-10-25 10:59:59 +01:00
|
|
|
}
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( "\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
static const char*
|
2015-02-19 09:46:48 +01:00
|
|
|
af_edge_flags_to_string( FT_UInt flags )
|
2007-06-11 07:37:35 +02:00
|
|
|
{
|
2007-06-11 23:15:09 +02:00
|
|
|
static char temp[32];
|
|
|
|
int pos = 0;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
|
|
|
|
if ( flags & AF_EDGE_ROUND )
|
|
|
|
{
|
2009-01-12 21:01:10 +01:00
|
|
|
ft_memcpy( temp + pos, "round", 5 );
|
2007-06-11 07:37:35 +02:00
|
|
|
pos += 5;
|
|
|
|
}
|
|
|
|
if ( flags & AF_EDGE_SERIF )
|
|
|
|
{
|
2007-06-11 23:15:09 +02:00
|
|
|
if ( pos > 0 )
|
2007-06-11 07:37:35 +02:00
|
|
|
temp[pos++] = ' ';
|
2009-01-12 21:01:10 +01:00
|
|
|
ft_memcpy( temp + pos, "serif", 5 );
|
2007-06-11 07:37:35 +02:00
|
|
|
pos += 5;
|
|
|
|
}
|
2007-06-11 23:15:09 +02:00
|
|
|
if ( pos == 0 )
|
2007-06-11 07:37:35 +02:00
|
|
|
return "normal";
|
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
temp[pos] = '\0';
|
2007-06-11 23:15:09 +02:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Dump the array of linked segments. */
|
|
|
|
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
void
|
2013-11-27 10:10:16 +01:00
|
|
|
af_glyph_hints_dump_segments( AF_GlyphHints hints,
|
|
|
|
FT_Bool to_stdout )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-01-13 09:45:00 +01:00
|
|
|
FT_Int dimension;
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
for ( dimension = 1; dimension >= 0; dimension-- )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_AxisHints axis = &hints->axis[dimension];
|
2012-07-05 10:30:41 +02:00
|
|
|
AF_Point points = hints->points;
|
|
|
|
AF_Edge edges = axis->edges;
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Segment segments = axis->segments;
|
|
|
|
AF_Segment limit = segments + axis->num_segments;
|
|
|
|
AF_Segment seg;
|
|
|
|
|
2015-10-25 10:59:59 +01:00
|
|
|
char buf1[16], buf2[16], buf3[16];
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( "Table of %s segments:\n",
|
|
|
|
dimension == AF_DIMENSION_HORZ ? "vertical"
|
|
|
|
: "horizontal" ));
|
2013-03-23 14:25:43 +01:00
|
|
|
if ( axis->num_segments )
|
2017-10-12 00:13:51 +02:00
|
|
|
{
|
2016-07-15 10:35:32 +02:00
|
|
|
AF_DUMP(( " index pos delta dir from to "
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXXX XXXXX XXXXX XXXXX XXXX XXXX" */
|
2016-07-15 10:35:32 +02:00
|
|
|
" link serif edge"
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXX XXXXX XXXX" */
|
2015-10-25 10:59:59 +01:00
|
|
|
" height extra flags\n" ));
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXXXX XXXXX XXXXXXXXXXX" */
|
|
|
|
}
|
2012-07-05 10:30:41 +02:00
|
|
|
else
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( " (none)\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
for ( seg = segments; seg < limit; seg++ )
|
2016-07-15 10:35:32 +02:00
|
|
|
AF_DUMP(( " %5d %5d %5d %5s %4d %4d"
|
2015-10-25 10:59:59 +01:00
|
|
|
" %4s %5s %4s"
|
|
|
|
" %6d %5d %11s\n",
|
2014-12-03 19:30:44 +01:00
|
|
|
AF_INDEX_NUM( seg, segments ),
|
2016-07-15 10:35:32 +02:00
|
|
|
seg->pos,
|
|
|
|
seg->delta,
|
2013-11-27 10:10:16 +01:00
|
|
|
af_dir_str( (AF_Direction)seg->dir ),
|
|
|
|
AF_INDEX_NUM( seg->first, points ),
|
|
|
|
AF_INDEX_NUM( seg->last, points ),
|
2015-10-25 10:59:59 +01:00
|
|
|
|
|
|
|
af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
|
|
|
|
af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
|
|
|
|
af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
|
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
seg->height,
|
|
|
|
seg->height - ( seg->max_coord - seg->min_coord ),
|
2015-02-19 09:46:48 +01:00
|
|
|
af_edge_flags_to_string( seg->flags ) ));
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( "\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-05-01 13:44:44 +02:00
|
|
|
/* Fetch number of segments. */
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
FT_Error
|
|
|
|
af_glyph_hints_get_num_segments( AF_GlyphHints hints,
|
|
|
|
FT_Int dimension,
|
|
|
|
FT_Int* num_segments )
|
|
|
|
{
|
|
|
|
AF_Dimension dim;
|
|
|
|
AF_AxisHints axis;
|
|
|
|
|
|
|
|
|
|
|
|
dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
|
|
|
|
|
|
|
|
axis = &hints->axis[dim];
|
|
|
|
*num_segments = axis->num_segments;
|
|
|
|
|
2013-03-14 11:21:17 +01:00
|
|
|
return FT_Err_Ok;
|
2011-05-01 13:44:44 +02:00
|
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Fetch offset of segments into user supplied offset array. */
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
FT_Error
|
|
|
|
af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
|
|
|
|
FT_Int dimension,
|
|
|
|
FT_Int idx,
|
2014-01-03 10:48:26 +01:00
|
|
|
FT_Pos *offset,
|
|
|
|
FT_Bool *is_blue,
|
|
|
|
FT_Pos *blue_offset )
|
2011-05-01 13:44:44 +02:00
|
|
|
{
|
|
|
|
AF_Dimension dim;
|
|
|
|
AF_AxisHints axis;
|
|
|
|
AF_Segment seg;
|
|
|
|
|
|
|
|
|
|
|
|
if ( !offset )
|
2013-03-14 10:27:35 +01:00
|
|
|
return FT_THROW( Invalid_Argument );
|
2011-05-01 13:44:44 +02:00
|
|
|
|
|
|
|
dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
|
|
|
|
|
|
|
|
axis = &hints->axis[dim];
|
|
|
|
|
|
|
|
if ( idx < 0 || idx >= axis->num_segments )
|
2013-03-14 10:27:35 +01:00
|
|
|
return FT_THROW( Invalid_Argument );
|
2011-05-01 13:44:44 +02:00
|
|
|
|
2014-01-03 10:48:26 +01:00
|
|
|
seg = &axis->segments[idx];
|
2017-09-09 08:08:47 +02:00
|
|
|
*offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
|
|
|
|
: seg->first->fy;
|
2014-01-03 10:48:26 +01:00
|
|
|
if ( seg->edge )
|
2018-09-25 09:10:09 +02:00
|
|
|
*is_blue = FT_BOOL( seg->edge->blue_edge );
|
2014-01-03 10:48:26 +01:00
|
|
|
else
|
|
|
|
*is_blue = FALSE;
|
|
|
|
|
|
|
|
if ( *is_blue )
|
2017-09-09 08:08:47 +02:00
|
|
|
*blue_offset = seg->edge->blue_edge->org;
|
2014-01-03 10:48:26 +01:00
|
|
|
else
|
|
|
|
*blue_offset = 0;
|
2011-05-01 13:44:44 +02:00
|
|
|
|
2013-03-14 11:21:17 +01:00
|
|
|
return FT_Err_Ok;
|
2011-05-01 13:44:44 +02:00
|
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Dump the array of linked edges. */
|
|
|
|
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
void
|
2013-11-27 10:10:16 +01:00
|
|
|
af_glyph_hints_dump_edges( AF_GlyphHints hints,
|
|
|
|
FT_Bool to_stdout )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
FT_Int dimension;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
for ( dimension = 1; dimension >= 0; dimension-- )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_AxisHints axis = &hints->axis[dimension];
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Edge edges = axis->edges;
|
|
|
|
AF_Edge limit = edges + axis->num_edges;
|
|
|
|
AF_Edge edge;
|
|
|
|
|
2015-10-25 10:59:59 +01:00
|
|
|
char buf1[16], buf2[16];
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
|
|
|
|
* since they have a constant X coordinate.
|
2005-03-02 12:24:23 +01:00
|
|
|
*/
|
2016-07-15 10:35:32 +02:00
|
|
|
if ( dimension == AF_DIMENSION_HORZ )
|
|
|
|
AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
|
|
|
|
"vertical",
|
|
|
|
65536.0 * 64.0 / hints->x_scale,
|
|
|
|
10.0 * hints->x_scale / 65536.0 / 64.0 ));
|
|
|
|
else
|
|
|
|
AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
|
|
|
|
"horizontal",
|
|
|
|
65536.0 * 64.0 / hints->y_scale,
|
|
|
|
10.0 * hints->y_scale / 65536.0 / 64.0 ));
|
|
|
|
|
2012-07-05 10:30:41 +02:00
|
|
|
if ( axis->num_edges )
|
2017-10-12 00:13:51 +02:00
|
|
|
{
|
2016-07-15 10:35:32 +02:00
|
|
|
AF_DUMP(( " index pos dir link serif"
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " XXXXX XXXX.XX XXXXX XXXX XXXXX" */
|
2016-07-15 10:35:32 +02:00
|
|
|
" blue opos pos flags\n" ));
|
2017-10-12 00:13:51 +02:00
|
|
|
/* " X XXXX.XX XXXX.XX XXXXXXXXXXX" */
|
|
|
|
}
|
2012-07-05 10:30:41 +02:00
|
|
|
else
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( " (none)\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
for ( edge = edges; edge < limit; edge++ )
|
2016-07-15 10:35:32 +02:00
|
|
|
AF_DUMP(( " %5d %7.2f %5s %4s %5s"
|
|
|
|
" %c %7.2f %7.2f %11s\n",
|
2014-12-03 19:30:44 +01:00
|
|
|
AF_INDEX_NUM( edge, edges ),
|
2013-11-27 10:10:16 +01:00
|
|
|
(int)edge->opos / 64.0,
|
|
|
|
af_dir_str( (AF_Direction)edge->dir ),
|
2015-10-25 10:59:59 +01:00
|
|
|
af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
|
|
|
|
af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
|
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
edge->blue_edge ? 'y' : 'n',
|
|
|
|
edge->opos / 64.0,
|
|
|
|
edge->pos / 64.0,
|
2015-02-19 09:46:48 +01:00
|
|
|
af_edge_flags_to_string( edge->flags ) ));
|
2013-11-27 10:10:16 +01:00
|
|
|
AF_DUMP(( "\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2011-03-19 15:27:04 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-11-27 10:10:16 +01:00
|
|
|
#undef AF_DUMP
|
2011-03-19 15:27:04 +01:00
|
|
|
|
2011-04-18 19:05:28 +02:00
|
|
|
#endif /* !FT_DEBUG_AUTOFIT */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Compute the direction value of a given vector. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( AF_Direction )
|
|
|
|
af_direction_compute( FT_Pos dx,
|
|
|
|
FT_Pos dy )
|
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
FT_Pos ll, ss; /* long and short arm lengths */
|
|
|
|
AF_Direction dir; /* candidate direction */
|
2005-10-28 18:14:14 +02:00
|
|
|
|
2006-05-18 00:55:04 +02:00
|
|
|
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
if ( dy >= dx )
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
if ( dy >= -dx )
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
dir = AF_DIR_UP;
|
|
|
|
ll = dy;
|
|
|
|
ss = dx;
|
2005-10-28 18:14:14 +02:00
|
|
|
}
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
else
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
dir = AF_DIR_LEFT;
|
|
|
|
ll = -dx;
|
|
|
|
ss = dy;
|
2005-10-28 18:14:14 +02:00
|
|
|
}
|
|
|
|
}
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
else /* dy < dx */
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
if ( dy >= -dx )
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
dir = AF_DIR_RIGHT;
|
|
|
|
ll = dx;
|
|
|
|
ss = dy;
|
2005-10-28 18:14:14 +02:00
|
|
|
}
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
else
|
2005-10-28 18:14:14 +02:00
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
dir = AF_DIR_DOWN;
|
2015-04-02 04:57:43 +02:00
|
|
|
ll = -dy;
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
ss = dx;
|
2005-10-28 18:14:14 +02:00
|
|
|
}
|
|
|
|
}
|
2005-11-12 08:34:40 +01:00
|
|
|
|
2015-04-02 04:57:43 +02:00
|
|
|
/* return no direction if arm lengths do not differ enough */
|
2012-07-04 13:51:32 +02:00
|
|
|
/* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
|
2015-04-02 04:57:43 +02:00
|
|
|
/* the long arm is never negative */
|
|
|
|
if ( ll <= 14 * FT_ABS( ss ) )
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
dir = AF_DIR_NONE;
|
2005-11-12 08:34:40 +01:00
|
|
|
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
return dir;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_glyph_hints_init( AF_GlyphHints hints,
|
|
|
|
FT_Memory memory )
|
|
|
|
{
|
2015-01-14 19:26:49 +01:00
|
|
|
/* no need to initialize the embedded items */
|
|
|
|
FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) );
|
2004-03-27 09:43:17 +01:00
|
|
|
hints->memory = memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_glyph_hints_done( AF_GlyphHints hints )
|
|
|
|
{
|
2015-04-01 13:13:56 +02:00
|
|
|
FT_Memory memory;
|
2012-07-06 19:38:44 +02:00
|
|
|
int dim;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
if ( !( hints && hints->memory ) )
|
|
|
|
return;
|
|
|
|
|
2015-04-01 13:13:56 +02:00
|
|
|
memory = hints->memory;
|
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* note that we don't need to free the segment and edge
|
|
|
|
* buffers since they are really within the hints->points array
|
2012-07-06 19:38:44 +02:00
|
|
|
*/
|
|
|
|
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
|
|
|
|
{
|
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
axis->num_segments = 0;
|
|
|
|
axis->max_segments = 0;
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->segments != axis->embedded.segments )
|
|
|
|
FT_FREE( axis->segments );
|
2005-03-01 16:48:29 +01:00
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
axis->num_edges = 0;
|
|
|
|
axis->max_edges = 0;
|
2015-01-14 19:36:02 +01:00
|
|
|
if ( axis->edges != axis->embedded.edges )
|
|
|
|
FT_FREE( axis->edges );
|
2012-07-06 19:38:44 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-01-14 19:26:49 +01:00
|
|
|
if ( hints->contours != hints->embedded.contours )
|
|
|
|
FT_FREE( hints->contours );
|
2012-07-06 19:38:44 +02:00
|
|
|
hints->max_contours = 0;
|
|
|
|
hints->num_contours = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-01-14 19:26:49 +01:00
|
|
|
if ( hints->points != hints->embedded.points )
|
|
|
|
FT_FREE( hints->points );
|
2012-07-06 19:38:44 +02:00
|
|
|
hints->max_points = 0;
|
2015-01-14 19:26:49 +01:00
|
|
|
hints->num_points = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
hints->memory = NULL;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Reset metrics. */
|
|
|
|
|
2004-06-04 19:41:59 +02:00
|
|
|
FT_LOCAL_DEF( void )
|
2013-12-18 12:59:35 +01:00
|
|
|
af_glyph_hints_rescale( AF_GlyphHints hints,
|
|
|
|
AF_StyleMetrics metrics )
|
2004-06-04 19:41:59 +02:00
|
|
|
{
|
2005-12-14 17:37:15 +01:00
|
|
|
hints->metrics = metrics;
|
|
|
|
hints->scaler_flags = metrics->scaler.flags;
|
2004-06-04 19:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Recompute all AF_Point in AF_GlyphHints from the definitions */
|
|
|
|
/* in a source outline. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
2005-03-02 12:24:23 +01:00
|
|
|
af_glyph_hints_reload( AF_GlyphHints hints,
|
2010-05-22 07:43:22 +02:00
|
|
|
FT_Outline* outline )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2013-03-14 11:21:17 +01:00
|
|
|
FT_Error error = FT_Err_Ok;
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_Point points;
|
2021-10-01 04:59:04 +02:00
|
|
|
FT_Int old_max, new_max;
|
2005-03-02 12:24:23 +01:00
|
|
|
FT_Fixed x_scale = hints->x_scale;
|
|
|
|
FT_Fixed y_scale = hints->y_scale;
|
|
|
|
FT_Pos x_delta = hints->x_delta;
|
|
|
|
FT_Pos y_delta = hints->y_delta;
|
|
|
|
FT_Memory memory = hints->memory;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
hints->num_points = 0;
|
|
|
|
hints->num_contours = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
hints->axis[0].num_segments = 0;
|
|
|
|
hints->axis[0].num_edges = 0;
|
|
|
|
hints->axis[1].num_segments = 0;
|
|
|
|
hints->axis[1].num_edges = 0;
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* first of all, reallocate the contours array if necessary */
|
2021-10-01 04:59:04 +02:00
|
|
|
new_max = outline->n_contours;
|
|
|
|
old_max = hints->max_contours;
|
2015-01-14 19:26:49 +01:00
|
|
|
|
|
|
|
if ( new_max <= AF_CONTOURS_EMBEDDED )
|
2015-02-06 08:46:06 +01:00
|
|
|
{
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !hints->contours )
|
2015-02-06 08:46:06 +01:00
|
|
|
{
|
|
|
|
hints->contours = hints->embedded.contours;
|
|
|
|
hints->max_contours = AF_CONTOURS_EMBEDDED;
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 19:26:49 +01:00
|
|
|
else if ( new_max > old_max )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2015-01-14 19:26:49 +01:00
|
|
|
if ( hints->contours == hints->embedded.contours )
|
|
|
|
hints->contours = NULL;
|
|
|
|
|
2021-10-01 04:59:04 +02:00
|
|
|
new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
|
|
|
|
goto Exit;
|
|
|
|
|
2021-10-01 04:59:04 +02:00
|
|
|
hints->max_contours = new_max;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* then reallocate the points arrays if necessary --
|
|
|
|
* note that we reserve two additional point positions, used to
|
|
|
|
* hint metrics appropriately
|
2005-03-02 12:24:23 +01:00
|
|
|
*/
|
2021-10-01 04:59:04 +02:00
|
|
|
new_max = outline->n_points + 2;
|
|
|
|
old_max = hints->max_points;
|
2015-01-14 19:26:49 +01:00
|
|
|
|
|
|
|
if ( new_max <= AF_POINTS_EMBEDDED )
|
2015-02-06 08:46:06 +01:00
|
|
|
{
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !hints->points )
|
2015-02-06 08:46:06 +01:00
|
|
|
{
|
|
|
|
hints->points = hints->embedded.points;
|
|
|
|
hints->max_points = AF_POINTS_EMBEDDED;
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 19:26:49 +01:00
|
|
|
else if ( new_max > old_max )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2015-01-14 19:26:49 +01:00
|
|
|
if ( hints->points == hints->embedded.points )
|
|
|
|
hints->points = NULL;
|
|
|
|
|
2021-10-01 04:59:04 +02:00
|
|
|
new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Exit;
|
|
|
|
|
2021-10-01 04:59:04 +02:00
|
|
|
hints->max_points = new_max;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hints->num_points = outline->n_points;
|
|
|
|
hints->num_contours = outline->n_contours;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* We can't rely on the value of `FT_Outline.flags' to know the fill */
|
|
|
|
/* direction used for a glyph, given that some fonts are broken (e.g., */
|
|
|
|
/* the Arphic ones). We thus recompute it each time we need to. */
|
|
|
|
/* */
|
|
|
|
hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
|
|
|
|
hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
|
|
|
|
hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hints->x_scale = x_scale;
|
|
|
|
hints->y_scale = y_scale;
|
|
|
|
hints->x_delta = x_delta;
|
|
|
|
hints->y_delta = y_delta;
|
|
|
|
|
|
|
|
points = hints->points;
|
|
|
|
if ( hints->num_points == 0 )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
{
|
|
|
|
AF_Point point;
|
|
|
|
AF_Point point_limit = points + hints->num_points;
|
|
|
|
|
2016-03-20 22:20:32 +01:00
|
|
|
/* value 20 in `near_limit' is heuristic */
|
|
|
|
FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM;
|
|
|
|
FT_Int near_limit = 20 * units_per_em / 2048;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
/* compute coordinates & Bezier flags, next and prev */
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-06-11 23:15:09 +02:00
|
|
|
FT_Vector* vec = outline->points;
|
|
|
|
char* tag = outline->tags;
|
2016-03-20 22:20:32 +01:00
|
|
|
FT_Short endpoint = outline->contours[0];
|
|
|
|
AF_Point end = points + endpoint;
|
2007-06-11 23:15:09 +02:00
|
|
|
AF_Point prev = end;
|
2007-06-11 07:37:35 +02:00
|
|
|
FT_Int contour_index = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( point = points; point < point_limit; point++, vec++, tag++ )
|
|
|
|
{
|
2016-03-20 22:20:32 +01:00
|
|
|
FT_Pos out_x, out_y;
|
|
|
|
|
|
|
|
|
2014-05-11 12:44:00 +02:00
|
|
|
point->in_dir = (FT_Char)AF_DIR_NONE;
|
|
|
|
point->out_dir = (FT_Char)AF_DIR_NONE;
|
|
|
|
|
* Jamfile: removing otvalid from the list of compiled modules
* include/freetype/internal/ftserv.h: added compiler pragmas to get rid
of annoying warnings with Visual C++ compiler in maximum warning mode
* src/autofit/afhints.c, src/autofit/aflatin.c, src/base/ftstroke.c,
src/bdf/bdfdrivr.c, src/cache/ftcbasic.c, src/cache/ftccmap.c,
src/cache/ftcmanag.c, src/cff/cffload.c, src/cid/cidload.c,
src/lzw/zopen.c, src/otvalid/otvgdef.c, src/pcf/pcfread.c,
src/sfnt/sfobjs.c, src/truetype/ttgxvar.c: removing compiler warnings
2005-05-01 12:11:32 +02:00
|
|
|
point->fx = (FT_Short)vec->x;
|
|
|
|
point->fy = (FT_Short)vec->y;
|
2004-03-27 09:43:17 +01:00
|
|
|
point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
|
|
|
|
point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
|
|
|
|
|
2016-03-21 19:39:14 +01:00
|
|
|
end->fx = (FT_Short)outline->points[endpoint].x;
|
|
|
|
end->fy = (FT_Short)outline->points[endpoint].y;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
switch ( FT_CURVE_TAG( *tag ) )
|
|
|
|
{
|
|
|
|
case FT_CURVE_TAG_CONIC:
|
|
|
|
point->flags = AF_FLAG_CONIC;
|
|
|
|
break;
|
|
|
|
case FT_CURVE_TAG_CUBIC:
|
|
|
|
point->flags = AF_FLAG_CUBIC;
|
|
|
|
break;
|
|
|
|
default:
|
2011-02-16 21:59:44 +01:00
|
|
|
point->flags = AF_FLAG_NONE;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2016-03-20 22:20:32 +01:00
|
|
|
out_x = point->fx - prev->fx;
|
|
|
|
out_y = point->fy - prev->fy;
|
|
|
|
|
|
|
|
if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
|
|
|
|
prev->flags |= AF_FLAG_NEAR;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
point->prev = prev;
|
2007-06-11 07:37:35 +02:00
|
|
|
prev->next = point;
|
|
|
|
prev = point;
|
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
if ( point == end )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( ++contour_index < outline->n_contours )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2016-03-20 22:20:32 +01:00
|
|
|
endpoint = outline->contours[contour_index];
|
2016-03-21 19:39:14 +01:00
|
|
|
end = points + endpoint;
|
|
|
|
prev = end;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2018-08-31 06:53:52 +02:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
|
|
|
point->before[0] = NULL;
|
|
|
|
point->before[1] = NULL;
|
|
|
|
point->after[0] = NULL;
|
|
|
|
point->after[1] = NULL;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* set up the contours array */
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
AF_Point* contour = hints->contours;
|
|
|
|
AF_Point* contour_limit = contour + hints->num_contours;
|
|
|
|
short* end = outline->contours;
|
|
|
|
short idx = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for ( ; contour < contour_limit; contour++, end++ )
|
|
|
|
{
|
|
|
|
contour[0] = points + idx;
|
|
|
|
idx = (short)( end[0] + 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2014-04-12 20:44:33 +02:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* Compute directions of `in' and `out' vectors.
|
2014-04-12 20:44:33 +02:00
|
|
|
*
|
2018-06-03 09:01:17 +02:00
|
|
|
* Note that distances between points that are very near to each
|
|
|
|
* other are accumulated. In other words, the auto-hinter either
|
|
|
|
* prepends the small vectors between near points to the first
|
|
|
|
* non-near vector, or the sum of small vector lengths exceeds a
|
|
|
|
* threshold, thus `grouping' the small vectors. All intermediate
|
|
|
|
* points are tagged as weak; the directions are adjusted also to
|
|
|
|
* be equal to the accumulated one.
|
2014-04-12 20:44:33 +02:00
|
|
|
*/
|
|
|
|
|
2016-03-20 22:20:32 +01:00
|
|
|
FT_Int near_limit2 = 2 * near_limit - 1;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
AF_Point* contour;
|
|
|
|
AF_Point* contour_limit = hints->contours + hints->num_contours;
|
2007-06-11 23:15:09 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
|
|
|
|
for ( contour = hints->contours; contour < contour_limit; contour++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2014-04-12 20:44:33 +02:00
|
|
|
AF_Point first = *contour;
|
|
|
|
AF_Point next, prev, curr;
|
|
|
|
|
|
|
|
FT_Pos out_x, out_y;
|
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
/* since the first point of a contour could be part of a */
|
|
|
|
/* series of near points, go backwards to find the first */
|
|
|
|
/* non-near point and adjust `first' */
|
|
|
|
|
|
|
|
point = first;
|
|
|
|
prev = first->prev;
|
|
|
|
|
|
|
|
while ( prev != first )
|
2007-06-11 07:37:35 +02:00
|
|
|
{
|
2014-04-12 20:44:33 +02:00
|
|
|
out_x = point->fx - prev->fx;
|
|
|
|
out_y = point->fy - prev->fy;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-05-11 08:00:25 +02:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* We use Taxicab metrics to measure the vector length.
|
2014-05-11 08:00:25 +02:00
|
|
|
*
|
2018-06-03 09:01:17 +02:00
|
|
|
* Note that the accumulated distances so far could have the
|
|
|
|
* opposite direction of the distance measured here. For this
|
|
|
|
* reason we use `near_limit2' for the comparison to get a
|
|
|
|
* non-near point even in the worst case.
|
2014-05-11 08:00:25 +02:00
|
|
|
*/
|
|
|
|
if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 )
|
2014-04-12 20:44:33 +02:00
|
|
|
break;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
point = prev;
|
|
|
|
prev = prev->prev;
|
|
|
|
}
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
/* adjust first point */
|
|
|
|
first = point;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
/* now loop over all points of the contour to get */
|
|
|
|
/* `in' and `out' vector directions */
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2016-03-20 22:20:32 +01:00
|
|
|
curr = first;
|
2014-05-11 08:00:25 +02:00
|
|
|
|
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* We abuse the `u' and `v' fields to store index deltas to the
|
|
|
|
* next and previous non-near point, respectively.
|
2014-05-11 08:00:25 +02:00
|
|
|
*
|
2018-06-03 09:01:17 +02:00
|
|
|
* To avoid problems with not having non-near points, we point to
|
|
|
|
* `first' by default as the next non-near point.
|
2014-05-11 08:00:25 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
curr->u = (FT_Pos)( first - curr );
|
|
|
|
first->v = -curr->u;
|
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
out_x = 0;
|
|
|
|
out_y = 0;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2015-04-04 04:38:11 +02:00
|
|
|
next = first;
|
|
|
|
do
|
2014-04-12 20:44:33 +02:00
|
|
|
{
|
|
|
|
AF_Direction out_dir;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
|
|
|
|
2015-04-04 04:38:11 +02:00
|
|
|
point = next;
|
2016-03-20 22:20:32 +01:00
|
|
|
next = point->next;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
out_x += next->fx - point->fx;
|
|
|
|
out_y += next->fy - point->fy;
|
|
|
|
|
|
|
|
if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
|
|
|
|
{
|
|
|
|
next->flags |= AF_FLAG_WEAK_INTERPOLATION;
|
|
|
|
continue;
|
2013-08-05 08:46:15 +02:00
|
|
|
}
|
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
curr->u = (FT_Pos)( next - curr );
|
|
|
|
next->v = -curr->u;
|
|
|
|
|
|
|
|
out_dir = af_direction_compute( out_x, out_y );
|
|
|
|
|
|
|
|
/* adjust directions for all points inbetween; */
|
|
|
|
/* the loop also updates position of `curr' */
|
|
|
|
curr->out_dir = (FT_Char)out_dir;
|
|
|
|
for ( curr = curr->next; curr != next; curr = curr->next )
|
|
|
|
{
|
|
|
|
curr->in_dir = (FT_Char)out_dir;
|
|
|
|
curr->out_dir = (FT_Char)out_dir;
|
|
|
|
}
|
|
|
|
next->in_dir = (FT_Char)out_dir;
|
|
|
|
|
2014-05-11 08:00:25 +02:00
|
|
|
curr->u = (FT_Pos)( first - curr );
|
|
|
|
first->v = -curr->u;
|
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
out_x = 0;
|
|
|
|
out_y = 0;
|
2015-04-04 04:38:11 +02:00
|
|
|
|
|
|
|
} while ( next != first );
|
2014-04-12 20:44:33 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* The next step is to `simplify' an outline's topology so that we
|
|
|
|
* can identify local extrema more reliably: A series of
|
|
|
|
* non-horizontal or non-vertical vectors pointing into the same
|
|
|
|
* quadrant are handled as a single, long vector. From a
|
|
|
|
* topological point of the view, the intermediate points are of no
|
|
|
|
* interest and thus tagged as weak.
|
2014-04-12 20:44:33 +02:00
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
{
|
|
|
|
if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
|
|
|
|
continue;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
if ( point->in_dir == AF_DIR_NONE &&
|
|
|
|
point->out_dir == AF_DIR_NONE )
|
2013-08-05 08:46:15 +02:00
|
|
|
{
|
2014-04-12 20:44:33 +02:00
|
|
|
/* check whether both vectors point into the same quadrant */
|
|
|
|
|
|
|
|
FT_Pos in_x, in_y;
|
|
|
|
FT_Pos out_x, out_y;
|
|
|
|
|
|
|
|
AF_Point next_u = point + point->u;
|
|
|
|
AF_Point prev_v = point + point->v;
|
|
|
|
|
|
|
|
|
|
|
|
in_x = point->fx - prev_v->fx;
|
|
|
|
in_y = point->fy - prev_v->fy;
|
|
|
|
|
|
|
|
out_x = next_u->fx - point->fx;
|
|
|
|
out_y = next_u->fy - point->fy;
|
2013-08-05 08:46:15 +02:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 )
|
|
|
|
{
|
|
|
|
/* yes, so tag current point as weak */
|
|
|
|
/* and update index deltas */
|
|
|
|
|
|
|
|
point->flags |= AF_FLAG_WEAK_INTERPOLATION;
|
|
|
|
|
|
|
|
prev_v->u = (FT_Pos)( next_u - prev_v );
|
|
|
|
next_u->v = -prev_v->u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
/*
|
2018-06-03 09:01:17 +02:00
|
|
|
* Finally, check for remaining weak points. Everything else not
|
|
|
|
* collected in edges so far is then implicitly classified as strong
|
|
|
|
* points.
|
2014-04-12 20:44:33 +02:00
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-12 20:44:33 +02:00
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
{
|
|
|
|
if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
|
|
|
|
continue;
|
2011-02-16 21:59:44 +01:00
|
|
|
|
2012-07-06 19:38:44 +02:00
|
|
|
if ( point->flags & AF_FLAG_CONTROL )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2013-08-05 08:46:15 +02:00
|
|
|
/* control points are always weak */
|
2004-03-27 09:43:17 +01:00
|
|
|
Is_Weak_Point:
|
|
|
|
point->flags |= AF_FLAG_WEAK_INTERPOLATION;
|
|
|
|
}
|
|
|
|
else if ( point->out_dir == point->in_dir )
|
|
|
|
{
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
if ( point->out_dir != AF_DIR_NONE )
|
2013-08-05 08:46:15 +02:00
|
|
|
{
|
2013-08-05 16:34:32 +02:00
|
|
|
/* current point lies on a horizontal or */
|
|
|
|
/* vertical segment (but doesn't start or end it) */
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
goto Is_Weak_Point;
|
2013-08-05 08:46:15 +02:00
|
|
|
}
|
* include/freetype/internal/tttypes.h, src/autofit/afangles.c,
src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/autofit/aftypes.h, src/base/ftcalc.c, src/base/ftoutln.c,
src/gzip/ftgzip.c, src/psaux/psconv.c, src/truetype/ttgload.c,
src/type1/t1gload.c:
this is a major patch used to drastically improve the performance
of loading glyphs. This both speeds up loading the glypn vector
themselves and the auto-fitter.
note that we've started using inline assembler with GCC to
implement FT_MulFix, given that this function is so damn
important for the engine's performance.
the resulting speed-up is about 25%.
2006-05-17 15:34:21 +02:00
|
|
|
|
2013-08-05 08:46:15 +02:00
|
|
|
{
|
2014-04-12 20:44:33 +02:00
|
|
|
AF_Point next_u = point + point->u;
|
|
|
|
AF_Point prev_v = point + point->v;
|
|
|
|
|
|
|
|
|
|
|
|
if ( ft_corner_is_flat( point->fx - prev_v->fx,
|
|
|
|
point->fy - prev_v->fy,
|
|
|
|
next_u->fx - point->fx,
|
|
|
|
next_u->fy - point->fy ) )
|
|
|
|
{
|
|
|
|
/* either the `in' or the `out' vector is much more */
|
|
|
|
/* dominant than the other one, so tag current point */
|
|
|
|
/* as weak and update index deltas */
|
|
|
|
|
|
|
|
prev_v->u = (FT_Pos)( next_u - prev_v );
|
|
|
|
next_u->v = -prev_v->u;
|
|
|
|
|
|
|
|
goto Is_Weak_Point;
|
|
|
|
}
|
2013-08-05 08:46:15 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
else if ( point->in_dir == -point->out_dir )
|
2013-08-05 08:46:15 +02:00
|
|
|
{
|
|
|
|
/* current point forms a spike */
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Is_Weak_Point;
|
2013-08-05 08:46:15 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Store the hinted outline in an FT_Outline structure. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
2005-03-02 12:24:23 +01:00
|
|
|
af_glyph_hints_save( AF_GlyphHints hints,
|
|
|
|
FT_Outline* outline )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
AF_Point point = hints->points;
|
|
|
|
AF_Point limit = point + hints->num_points;
|
|
|
|
FT_Vector* vec = outline->points;
|
|
|
|
char* tag = outline->tags;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( ; point < limit; point++, vec++, tag++ )
|
|
|
|
{
|
* Jamfile: removing otvalid from the list of compiled modules
* include/freetype/internal/ftserv.h: added compiler pragmas to get rid
of annoying warnings with Visual C++ compiler in maximum warning mode
* src/autofit/afhints.c, src/autofit/aflatin.c, src/base/ftstroke.c,
src/bdf/bdfdrivr.c, src/cache/ftcbasic.c, src/cache/ftccmap.c,
src/cache/ftcmanag.c, src/cff/cffload.c, src/cid/cidload.c,
src/lzw/zopen.c, src/otvalid/otvgdef.c, src/pcf/pcfread.c,
src/sfnt/sfobjs.c, src/truetype/ttgxvar.c: removing compiler warnings
2005-05-01 12:11:32 +02:00
|
|
|
vec->x = point->x;
|
|
|
|
vec->y = point->y;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( point->flags & AF_FLAG_CONIC )
|
|
|
|
tag[0] = FT_CURVE_TAG_CONIC;
|
|
|
|
else if ( point->flags & AF_FLAG_CUBIC )
|
|
|
|
tag[0] = FT_CURVE_TAG_CUBIC;
|
|
|
|
else
|
|
|
|
tag[0] = FT_CURVE_TAG_ON;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/****************************************************************
|
|
|
|
*
|
|
|
|
* EDGE POINT GRID-FITTING
|
|
|
|
*
|
|
|
|
****************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Align all points of an edge to the same coordinate value, */
|
|
|
|
/* either horizontally or vertically. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_glyph_hints_align_edge_points( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
AF_AxisHints axis = & hints->axis[dim];
|
|
|
|
AF_Segment segments = axis->segments;
|
[autofit, pshinter] Use `FT_OFFSET`.
This avoids
```
runtime error: applying zero offset to null pointer
```
warnings of clang's undefined behaviour sanitizer.
* src/autofit/afcjk.c (af_cjk_hints_link_segments,
af_cjk_hints_compute_edges, af_cjk_hints_compute_blue_edges,
af_cjk_hint_edges, af_cjk_align_edge_points): Do it.
* src/autofit/afhints.c (af_glyph_hints_align_edge_points,
af_glyph_hints_align_strong_points): Ditto.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_hints_link_segments, af_latin_hints_compute_edges,
af_latin_hints_compute_blue_edges, af_latin_hint_edges): Ditto.
* src/pshinter/pshalgo.c (psh_hint_table_init): Ditto.
2022-01-07 06:41:36 +01:00
|
|
|
AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
|
2007-06-11 07:37:35 +02:00
|
|
|
AF_Segment seg;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
for ( seg = segments; seg < segment_limit; seg++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
AF_Edge edge = seg->edge;
|
|
|
|
AF_Point point, first, last;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !edge )
|
2007-06-11 07:37:35 +02:00
|
|
|
continue;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
first = seg->first;
|
|
|
|
last = seg->last;
|
|
|
|
point = first;
|
2004-03-27 09:43:17 +01:00
|
|
|
for (;;)
|
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
point->x = edge->pos;
|
|
|
|
point->flags |= AF_FLAG_TOUCH_X;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( point == last )
|
2004-03-27 09:43:17 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
point = point->next;
|
|
|
|
}
|
2007-06-11 07:37:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for ( seg = segments; seg < segment_limit; seg++ )
|
|
|
|
{
|
|
|
|
AF_Edge edge = seg->edge;
|
|
|
|
AF_Point point, first, last;
|
|
|
|
|
|
|
|
|
2016-12-26 17:08:17 +01:00
|
|
|
if ( !edge )
|
2007-06-11 07:37:35 +02:00
|
|
|
continue;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
first = seg->first;
|
|
|
|
last = seg->last;
|
|
|
|
point = first;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
point->y = edge->pos;
|
|
|
|
point->flags |= AF_FLAG_TOUCH_Y;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( point == last )
|
|
|
|
break;
|
|
|
|
|
|
|
|
point = point->next;
|
|
|
|
}
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/****************************************************************
|
|
|
|
*
|
|
|
|
* STRONG POINT INTERPOLATION
|
|
|
|
*
|
|
|
|
****************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Hint the strong points -- this is equivalent to the TrueType `IP' */
|
|
|
|
/* hinting instruction. */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_glyph_hints_align_strong_points( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
|
|
|
AF_Point points = hints->points;
|
|
|
|
AF_Point point_limit = points + hints->num_points;
|
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
|
|
|
AF_Edge edges = axis->edges;
|
[autofit, pshinter] Use `FT_OFFSET`.
This avoids
```
runtime error: applying zero offset to null pointer
```
warnings of clang's undefined behaviour sanitizer.
* src/autofit/afcjk.c (af_cjk_hints_link_segments,
af_cjk_hints_compute_edges, af_cjk_hints_compute_blue_edges,
af_cjk_hint_edges, af_cjk_align_edge_points): Do it.
* src/autofit/afhints.c (af_glyph_hints_align_edge_points,
af_glyph_hints_align_strong_points): Ditto.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_hints_link_segments, af_latin_hints_compute_edges,
af_latin_hints_compute_blue_edges, af_latin_hint_edges): Ditto.
* src/pshinter/pshalgo.c (psh_hint_table_init): Ditto.
2022-01-07 06:41:36 +01:00
|
|
|
AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
|
2015-02-19 09:46:48 +01:00
|
|
|
FT_UInt touch_flag;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
touch_flag = AF_FLAG_TOUCH_X;
|
|
|
|
else
|
|
|
|
touch_flag = AF_FLAG_TOUCH_Y;
|
|
|
|
|
|
|
|
if ( edges < edge_limit )
|
|
|
|
{
|
|
|
|
AF_Point point;
|
|
|
|
AF_Edge edge;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
{
|
|
|
|
FT_Pos u, ou, fu; /* point position */
|
|
|
|
FT_Pos delta;
|
|
|
|
|
|
|
|
|
|
|
|
if ( point->flags & touch_flag )
|
|
|
|
continue;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* if this point is candidate to weak interpolation, we */
|
2004-03-27 09:43:17 +01:00
|
|
|
/* interpolate it after all strong points have been processed */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2014-09-24 19:06:13 +02:00
|
|
|
if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( dim == AF_DIMENSION_VERT )
|
|
|
|
{
|
|
|
|
u = point->fy;
|
|
|
|
ou = point->oy;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u = point->fx;
|
|
|
|
ou = point->ox;
|
|
|
|
}
|
|
|
|
|
|
|
|
fu = u;
|
|
|
|
|
|
|
|
/* is the point before the first edge? */
|
|
|
|
edge = edges;
|
|
|
|
delta = edge->fpos - u;
|
|
|
|
if ( delta >= 0 )
|
|
|
|
{
|
|
|
|
u = edge->pos - ( edge->opos - ou );
|
2018-08-30 09:56:09 +02:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
|
|
|
point->before[dim] = edge;
|
|
|
|
point->after[dim] = NULL;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Store_Point;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is the point after the last edge? */
|
|
|
|
edge = edge_limit - 1;
|
|
|
|
delta = u - edge->fpos;
|
|
|
|
if ( delta >= 0 )
|
|
|
|
{
|
|
|
|
u = edge->pos + ( ou - edge->opos );
|
2018-08-30 09:56:09 +02:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
|
|
|
point->before[dim] = NULL;
|
|
|
|
point->after[dim] = edge;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Store_Point;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2009-07-31 17:32:07 +02:00
|
|
|
FT_PtrDist min, max, mid;
|
|
|
|
FT_Pos fpos;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* find enclosing edges */
|
|
|
|
min = 0;
|
|
|
|
max = edge_limit - edges;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
#if 1
|
2011-02-16 21:59:44 +01:00
|
|
|
/* for a small number of edges, a linear search is better */
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( max <= 8 )
|
|
|
|
{
|
2009-07-31 17:32:07 +02:00
|
|
|
FT_PtrDist nn;
|
2007-06-11 07:37:35 +02:00
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
for ( nn = 0; nn < max; nn++ )
|
|
|
|
if ( edges[nn].fpos >= u )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( edges[nn].fpos == u )
|
|
|
|
{
|
|
|
|
u = edges[nn].pos;
|
|
|
|
goto Store_Point;
|
|
|
|
}
|
|
|
|
min = nn;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
while ( min < max )
|
|
|
|
{
|
|
|
|
mid = ( max + min ) >> 1;
|
|
|
|
edge = edges + mid;
|
|
|
|
fpos = edge->fpos;
|
|
|
|
|
|
|
|
if ( u < fpos )
|
|
|
|
max = mid;
|
|
|
|
else if ( u > fpos )
|
|
|
|
min = mid + 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* we are on the edge */
|
|
|
|
u = edge->pos;
|
2018-08-30 09:56:09 +02:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
|
|
|
point->before[dim] = NULL;
|
|
|
|
point->after[dim] = NULL;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Store_Point;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* point is not on an edge */
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
AF_Edge before = edges + min - 1;
|
|
|
|
AF_Edge after = edges + min + 0;
|
|
|
|
|
|
|
|
|
2018-08-30 09:56:09 +02:00
|
|
|
#ifdef FT_DEBUG_AUTOFIT
|
|
|
|
point->before[dim] = before;
|
|
|
|
point->after[dim] = after;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* assert( before && after && before != after ) */
|
|
|
|
if ( before->scale == 0 )
|
|
|
|
before->scale = FT_DivFix( after->pos - before->pos,
|
|
|
|
after->fpos - before->fpos );
|
|
|
|
|
|
|
|
u = before->pos + FT_MulFix( fu - before->fpos,
|
|
|
|
before->scale );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Store_Point:
|
|
|
|
/* save the point position */
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
point->x = u;
|
|
|
|
else
|
|
|
|
point->y = u;
|
|
|
|
|
|
|
|
point->flags |= touch_flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/****************************************************************
|
|
|
|
*
|
|
|
|
* WEAK POINT INTERPOLATION
|
|
|
|
*
|
|
|
|
****************************************************************/
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Shift the original coordinates of all points between `p1' and */
|
|
|
|
/* `p2' to get hinted coordinates, using the same difference as */
|
|
|
|
/* given by `ref'. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
|
|
|
af_iup_shift( AF_Point p1,
|
|
|
|
AF_Point p2,
|
|
|
|
AF_Point ref )
|
|
|
|
{
|
|
|
|
AF_Point p;
|
|
|
|
FT_Pos delta = ref->u - ref->v;
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
if ( delta == 0 )
|
2007-06-11 07:37:35 +02:00
|
|
|
return;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
for ( p = p1; p < ref; p++ )
|
|
|
|
p->u = p->v + delta;
|
|
|
|
|
|
|
|
for ( p = ref + 1; p <= p2; p++ )
|
|
|
|
p->u = p->v + delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Interpolate the original coordinates of all points between `p1' and */
|
|
|
|
/* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
|
|
|
|
/* reference points. The `u' and `v' members are the current and */
|
|
|
|
/* original coordinate values, respectively. */
|
|
|
|
/* */
|
|
|
|
/* Details can be found in the TrueType bytecode specification. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
|
|
|
af_iup_interp( AF_Point p1,
|
|
|
|
AF_Point p2,
|
|
|
|
AF_Point ref1,
|
|
|
|
AF_Point ref2 )
|
|
|
|
{
|
|
|
|
AF_Point p;
|
2015-04-30 03:57:30 +02:00
|
|
|
FT_Pos u, v1, v2, u1, u2, d1, d2;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
if ( p1 > p2 )
|
|
|
|
return;
|
|
|
|
|
2015-04-30 03:57:30 +02:00
|
|
|
if ( ref1->v > ref2->v )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2015-04-30 03:57:30 +02:00
|
|
|
p = ref1;
|
|
|
|
ref1 = ref2;
|
|
|
|
ref2 = p;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2015-04-30 03:57:30 +02:00
|
|
|
v1 = ref1->v;
|
|
|
|
v2 = ref2->v;
|
|
|
|
u1 = ref1->u;
|
|
|
|
u2 = ref2->u;
|
|
|
|
d1 = u1 - v1;
|
|
|
|
d2 = u2 - v2;
|
|
|
|
|
|
|
|
if ( u1 == u2 || v1 == v2 )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
for ( p = p1; p <= p2; p++ )
|
|
|
|
{
|
|
|
|
u = p->v;
|
|
|
|
|
|
|
|
if ( u <= v1 )
|
|
|
|
u += d1;
|
|
|
|
else if ( u >= v2 )
|
|
|
|
u += d2;
|
|
|
|
else
|
2015-04-30 03:57:30 +02:00
|
|
|
u = u1;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
p->u = u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-04-30 03:57:30 +02:00
|
|
|
FT_Fixed scale = FT_DivFix( u2 - u1, v2 - v1 );
|
|
|
|
|
2015-05-28 17:31:15 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( p = p1; p <= p2; p++ )
|
|
|
|
{
|
|
|
|
u = p->v;
|
|
|
|
|
2015-04-30 03:57:30 +02:00
|
|
|
if ( u <= v1 )
|
2004-03-27 09:43:17 +01:00
|
|
|
u += d1;
|
2015-04-30 03:57:30 +02:00
|
|
|
else if ( u >= v2 )
|
|
|
|
u += d2;
|
2004-03-27 09:43:17 +01:00
|
|
|
else
|
2015-04-30 03:57:30 +02:00
|
|
|
u = u1 + FT_MulFix( u - v1, scale );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
p->u = u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* Hint the weak points -- this is equivalent to the TrueType `IUP' */
|
|
|
|
/* hinting instruction. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_glyph_hints_align_weak_points( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
AF_Point points = hints->points;
|
|
|
|
AF_Point point_limit = points + hints->num_points;
|
|
|
|
AF_Point* contour = hints->contours;
|
|
|
|
AF_Point* contour_limit = contour + hints->num_contours;
|
2015-02-19 09:46:48 +01:00
|
|
|
FT_UInt touch_flag;
|
2005-03-03 18:09:08 +01:00
|
|
|
AF_Point point;
|
|
|
|
AF_Point end_point;
|
|
|
|
AF_Point first_point;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* PASS 1: Move segment points to edge positions */
|
|
|
|
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
touch_flag = AF_FLAG_TOUCH_X;
|
|
|
|
|
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
{
|
|
|
|
point->u = point->x;
|
|
|
|
point->v = point->ox;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
touch_flag = AF_FLAG_TOUCH_Y;
|
|
|
|
|
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
{
|
|
|
|
point->u = point->y;
|
|
|
|
point->v = point->oy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ; contour < contour_limit; contour++ )
|
|
|
|
{
|
2007-06-11 23:15:09 +02:00
|
|
|
AF_Point first_touched, last_touched;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
point = *contour;
|
|
|
|
end_point = point->prev;
|
|
|
|
first_point = point;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
/* find first touched point */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if ( point > end_point ) /* no touched point in contour */
|
|
|
|
goto NextContour;
|
|
|
|
|
|
|
|
if ( point->flags & touch_flag )
|
|
|
|
break;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
point++;
|
2007-06-11 07:37:35 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
first_touched = point;
|
|
|
|
|
|
|
|
for (;;)
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2011-02-16 21:59:44 +01:00
|
|
|
FT_ASSERT( point <= end_point &&
|
2007-06-11 23:15:09 +02:00
|
|
|
( point->flags & touch_flag ) != 0 );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-16 21:59:44 +01:00
|
|
|
/* skip any touched neighbours */
|
|
|
|
while ( point < end_point &&
|
|
|
|
( point[1].flags & touch_flag ) != 0 )
|
2007-06-11 07:37:35 +02:00
|
|
|
point++;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
last_touched = point;
|
|
|
|
|
|
|
|
/* find the next touched point, if any */
|
2011-02-16 21:59:44 +01:00
|
|
|
point++;
|
2007-06-11 07:37:35 +02:00
|
|
|
for (;;)
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( point > end_point )
|
|
|
|
goto EndContour;
|
|
|
|
|
2007-06-11 23:15:09 +02:00
|
|
|
if ( ( point->flags & touch_flag ) != 0 )
|
2007-06-11 07:37:35 +02:00
|
|
|
break;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
point++;
|
|
|
|
}
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
/* interpolate between last_touched and point */
|
|
|
|
af_iup_interp( last_touched + 1, point - 1,
|
|
|
|
last_touched, point );
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2007-06-11 07:37:35 +02:00
|
|
|
|
|
|
|
EndContour:
|
|
|
|
/* special case: only one point was touched */
|
|
|
|
if ( last_touched == first_touched )
|
|
|
|
af_iup_shift( first_point, end_point, first_touched );
|
2011-02-16 21:59:44 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
else /* interpolate the last part */
|
|
|
|
{
|
|
|
|
if ( last_touched < end_point )
|
|
|
|
af_iup_interp( last_touched + 1, end_point,
|
|
|
|
last_touched, first_touched );
|
|
|
|
|
|
|
|
if ( first_touched > points )
|
|
|
|
af_iup_interp( first_point, first_touched - 1,
|
|
|
|
last_touched, first_touched );
|
|
|
|
}
|
|
|
|
|
|
|
|
NextContour:
|
|
|
|
;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* now save the interpolated values back to x/y */
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
point->x = point->u;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for ( point = points; point < point_limit; point++ )
|
|
|
|
point->y = point->u;
|
|
|
|
}
|
|
|
|
}
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2006-01-22 07:58:16 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* END */
|