2005-03-03 18:09:08 +01:00
|
|
|
/***************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* aflatin.c */
|
|
|
|
/* */
|
2013-12-19 15:24:39 +01:00
|
|
|
/* Auto-fitter hinting routines for latin writing system (body). */
|
2005-03-03 18:09:08 +01:00
|
|
|
/* */
|
2015-01-17 20:41:43 +01:00
|
|
|
/* Copyright 2003-2015 by */
|
2005-03-03 18:09:08 +01: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. */
|
|
|
|
/* */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
|
2009-09-25 16:57:30 +02:00
|
|
|
#include <ft2build.h>
|
2009-04-27 19:40:35 +02:00
|
|
|
#include FT_ADVANCES_H
|
2011-04-18 19:05:28 +02:00
|
|
|
#include FT_INTERNAL_DEBUG_H
|
2009-04-27 19:40:35 +02:00
|
|
|
|
2012-10-20 08:34:57 +02:00
|
|
|
#include "afglobal.h"
|
2013-12-19 15:24:17 +01:00
|
|
|
#include "afpic.h"
|
2004-03-27 09:43:17 +01:00
|
|
|
#include "aflatin.h"
|
2005-03-23 17:45:24 +01:00
|
|
|
#include "aferrors.h"
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2011-03-02 03:52:36 +01:00
|
|
|
#ifdef AF_CONFIG_OPTION_USE_WARPER
|
2006-01-21 15:31:45 +01:00
|
|
|
#include "afwarp.h"
|
|
|
|
#endif
|
|
|
|
|
2006-01-22 07:58:16 +01:00
|
|
|
|
2011-04-18 19:05:28 +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. */
|
|
|
|
/* */
|
|
|
|
#undef FT_COMPONENT
|
|
|
|
#define FT_COMPONENT trace_aflatin
|
|
|
|
|
|
|
|
|
2015-08-05 21:53:50 +02:00
|
|
|
/* needed for computation of round vs. flat segments */
|
|
|
|
#define FLAT_THRESHOLD( x ) ( x / 14 )
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** L A T I N G L O B A L M E T R I C S *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
|
|
|
|
/* Find segments and links, compute all stem widths, and initialize */
|
|
|
|
/* standard width and height for the glyph with given charcode. */
|
|
|
|
|
2006-02-09 15:17:04 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_metrics_init_widths( AF_LatinMetrics metrics,
|
2012-10-24 14:22:14 +02:00
|
|
|
FT_Face face )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
/* scan the array of segments in each direction */
|
|
|
|
AF_GlyphHintsRec hints[1];
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2013-08-26 18:54:05 +02:00
|
|
|
FT_TRACE5(( "\n"
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
"latin standard widths computation (style `%s')\n"
|
2013-12-31 09:45:10 +01:00
|
|
|
"=====================================================\n"
|
2013-08-26 18:54:05 +02:00
|
|
|
"\n",
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
af_style_names[metrics->root.style_class->style] ));
|
2012-11-15 16:37:05 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
af_glyph_hints_init( hints, face->memory );
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
|
|
|
|
metrics->axis[AF_DIMENSION_VERT].width_count = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
{
|
2012-10-24 14:22:14 +02:00
|
|
|
FT_Error error;
|
2013-12-31 08:16:57 +01:00
|
|
|
FT_ULong glyph_index;
|
2012-10-24 14:22:14 +02:00
|
|
|
int dim;
|
|
|
|
AF_LatinMetricsRec dummy[1];
|
|
|
|
AF_Scaler scaler = &dummy->root.scaler;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-12-20 18:35:35 +01:00
|
|
|
#ifdef FT_CONFIG_OPTION_PIC
|
|
|
|
AF_FaceGlobals globals = metrics->root.globals;
|
|
|
|
#endif
|
|
|
|
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
AF_StyleClass style_class = metrics->root.style_class;
|
|
|
|
AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET
|
|
|
|
[style_class->script];
|
2005-03-02 12:24:23 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
void* shaper_buf;
|
2015-12-06 09:58:18 +01:00
|
|
|
const char* p;
|
2014-01-26 09:45:23 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2015-12-06 09:58:18 +01:00
|
|
|
FT_ULong ch;
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
#endif
|
2015-12-06 09:58:18 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
p = script_class->standard_charstring;
|
|
|
|
shaper_buf = af_shaper_buf_create( face );
|
2014-01-26 09:45:23 +01:00
|
|
|
|
|
|
|
/*
|
2015-12-06 09:58:18 +01:00
|
|
|
* We check a list of standard characters to catch features like
|
|
|
|
* `c2sc' (small caps from caps) that don't contain lowercase letters
|
|
|
|
* by definition, or other features that mainly operate on numerals.
|
|
|
|
* The first match wins.
|
2014-01-26 09:45:23 +01:00
|
|
|
*/
|
2013-12-19 15:24:17 +01:00
|
|
|
|
2015-12-06 09:58:18 +01:00
|
|
|
glyph_index = 0;
|
|
|
|
while ( *p )
|
2014-01-26 09:45:23 +01:00
|
|
|
{
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
unsigned int num_idx;
|
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
const char* p_old;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2015-12-06 09:58:18 +01:00
|
|
|
while ( *p == ' ' )
|
|
|
|
p++;
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
p_old = p;
|
|
|
|
GET_UTF8_CHAR( ch, p_old );
|
|
|
|
#endif
|
2015-12-06 09:58:18 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
/* reject input that maps to more than a single glyph */
|
|
|
|
p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
|
|
|
|
if ( num_idx > 1 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* otherwise exit loop if we have a result */
|
|
|
|
glyph_index = af_shaper_get_elem( &metrics->root,
|
|
|
|
shaper_buf,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL );
|
2015-12-06 09:58:18 +01:00
|
|
|
if ( glyph_index )
|
|
|
|
break;
|
2014-01-26 09:45:23 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
af_shaper_buf_destroy( face, shaper_buf );
|
|
|
|
|
2015-12-06 09:58:18 +01:00
|
|
|
if ( !glyph_index )
|
|
|
|
goto Exit;
|
|
|
|
|
2013-08-25 13:07:08 +02:00
|
|
|
FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
|
2015-12-06 09:58:18 +01:00
|
|
|
ch, glyph_index ));
|
2012-11-15 16:37:05 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
|
|
|
|
if ( error || face->glyph->outline.n_points <= 0 )
|
|
|
|
goto Exit;
|
|
|
|
|
2004-06-04 19:41:59 +02:00
|
|
|
FT_ZERO( dummy );
|
|
|
|
|
2006-02-11 14:22:37 +01:00
|
|
|
dummy->units_per_em = metrics->units_per_em;
|
2011-02-26 18:39:10 +01:00
|
|
|
|
|
|
|
scaler->x_scale = 0x10000L;
|
|
|
|
scaler->y_scale = 0x10000L;
|
|
|
|
scaler->x_delta = 0;
|
|
|
|
scaler->y_delta = 0;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
scaler->face = face;
|
2005-03-03 18:09:08 +01:00
|
|
|
scaler->render_mode = FT_RENDER_MODE_NORMAL;
|
2004-03-27 09:43:17 +01:00
|
|
|
scaler->flags = 0;
|
|
|
|
|
2013-12-18 12:59:35 +01:00
|
|
|
af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
|
2004-06-04 19:41:59 +02:00
|
|
|
|
2010-05-22 07:43:22 +02:00
|
|
|
error = af_glyph_hints_reload( hints, &face->glyph->outline );
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_LatinAxis axis = &metrics->axis[dim];
|
|
|
|
AF_AxisHints axhints = &hints->axis[dim];
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Segment seg, limit, link;
|
2006-02-11 13:12:02 +01:00
|
|
|
FT_UInt num_widths = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
error = af_latin_hints_compute_segments( hints,
|
|
|
|
(AF_Dimension)dim );
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
|
|
|
|
2014-04-05 16:27:19 +02:00
|
|
|
/*
|
|
|
|
* We assume that the glyphs selected for the stem width
|
|
|
|
* computation are `featureless' enough so that the linking
|
|
|
|
* algorithm works fine without adjustments of its scoring
|
|
|
|
* function.
|
|
|
|
*/
|
2005-03-03 18:09:08 +01:00
|
|
|
af_latin_hints_link_segments( hints,
|
2014-04-05 16:27:19 +02:00
|
|
|
0,
|
|
|
|
NULL,
|
2005-03-03 18:09:08 +01:00
|
|
|
(AF_Dimension)dim );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
seg = axhints->segments;
|
|
|
|
limit = seg + axhints->num_segments;
|
|
|
|
|
|
|
|
for ( ; seg < limit; seg++ )
|
|
|
|
{
|
|
|
|
link = seg->link;
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* we only consider stem segments there! */
|
|
|
|
if ( link && link->link == seg && link > seg )
|
|
|
|
{
|
|
|
|
FT_Pos dist;
|
|
|
|
|
|
|
|
|
|
|
|
dist = seg->pos - link->pos;
|
|
|
|
if ( dist < 0 )
|
|
|
|
dist = -dist;
|
|
|
|
|
|
|
|
if ( num_widths < AF_LATIN_MAX_WIDTHS )
|
2011-04-02 07:15:33 +02:00
|
|
|
axis->widths[num_widths++].org = dist;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-03 11:54:12 +02:00
|
|
|
/* this also replaces multiple almost identical stem widths */
|
2013-08-25 13:07:08 +02:00
|
|
|
/* with a single one (the value 100 is heuristic) */
|
2012-07-03 11:54:12 +02:00
|
|
|
af_sort_and_quantize_widths( &num_widths, axis->widths,
|
|
|
|
dummy->units_per_em / 100 );
|
2004-03-27 09:43:17 +01:00
|
|
|
axis->width_count = num_widths;
|
2006-02-11 13:12:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-25 13:07:08 +02:00
|
|
|
Exit:
|
2006-02-11 13:12:02 +01:00
|
|
|
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
|
|
|
|
{
|
|
|
|
AF_LatinAxis axis = &metrics->axis[dim];
|
|
|
|
FT_Pos stdw;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2013-08-25 13:07:08 +02:00
|
|
|
stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
|
|
|
|
: AF_LATIN_CONSTANT( metrics, 50 );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-02-11 13:12:02 +01:00
|
|
|
/* let's try 20% of the smallest width */
|
|
|
|
axis->edge_distance_threshold = stdw / 5;
|
2007-04-02 15:13:54 +02:00
|
|
|
axis->standard_width = stdw;
|
|
|
|
axis->extra_light = 0;
|
2012-11-15 16:37:05 +01:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
{
|
|
|
|
FT_UInt i;
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE5(( "%s widths:\n",
|
|
|
|
dim == AF_DIMENSION_VERT ? "horizontal"
|
|
|
|
: "vertical" ));
|
|
|
|
|
|
|
|
FT_TRACE5(( " %d (standard)", axis->standard_width ));
|
|
|
|
for ( i = 1; i < axis->width_count; i++ )
|
|
|
|
FT_TRACE5(( " %d", axis->widths[i].org ));
|
|
|
|
|
|
|
|
FT_TRACE5(( "\n" ));
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-15 16:37:05 +01:00
|
|
|
FT_TRACE5(( "\n" ));
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
af_glyph_hints_done( hints );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Find all blue zones. Flat segments give the reference points, */
|
|
|
|
/* round segments the overshoot positions. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
|
|
|
af_latin_metrics_init_blues( AF_LatinMetrics metrics,
|
|
|
|
FT_Face face )
|
|
|
|
{
|
2013-08-25 08:37:47 +02:00
|
|
|
FT_Pos flats [AF_BLUE_STRING_MAX_LEN];
|
|
|
|
FT_Pos rounds[AF_BLUE_STRING_MAX_LEN];
|
2013-08-25 13:07:08 +02:00
|
|
|
|
2015-02-19 10:44:18 +01:00
|
|
|
FT_UInt num_flats;
|
|
|
|
FT_UInt num_rounds;
|
2013-08-25 13:07:08 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_LatinBlue blue;
|
|
|
|
FT_Error error;
|
2013-08-25 13:07:08 +02:00
|
|
|
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
|
2012-08-05 10:58:02 +02:00
|
|
|
FT_Outline outline;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
AF_StyleClass sc = metrics->root.style_class;
|
2013-12-19 15:24:17 +01:00
|
|
|
|
|
|
|
AF_Blue_Stringset bss = sc->blue_stringset;
|
2013-08-25 08:37:47 +02:00
|
|
|
const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2015-08-05 21:53:50 +02:00
|
|
|
FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
void* shaper_buf;
|
|
|
|
|
2013-08-25 08:37:47 +02:00
|
|
|
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
/* we walk over the blue character strings as specified in the */
|
|
|
|
/* style's entry in the `af_blue_stringset' array */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-08-25 13:07:08 +02:00
|
|
|
FT_TRACE5(( "latin blue zones computation\n"
|
|
|
|
"============================\n"
|
2013-08-25 08:37:47 +02:00
|
|
|
"\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
shaper_buf = af_shaper_buf_create( face );
|
|
|
|
|
2013-08-25 08:37:47 +02:00
|
|
|
for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2013-08-25 08:37:47 +02:00
|
|
|
const char* p = &af_blue_strings[bs->string];
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Pos* blue_ref;
|
|
|
|
FT_Pos* blue_shoot;
|
2015-11-08 08:37:51 +01:00
|
|
|
FT_Pos ascender;
|
|
|
|
FT_Pos descender;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2013-10-12 10:33:04 +02:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
{
|
|
|
|
FT_Bool have_flag = 0;
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE5(( "blue zone %d", axis->blue_count ));
|
|
|
|
|
|
|
|
if ( bs->properties )
|
|
|
|
{
|
|
|
|
FT_TRACE5(( " (" ));
|
|
|
|
|
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
FT_TRACE5(( "top" ));
|
|
|
|
have_flag = 1;
|
|
|
|
}
|
2015-12-09 20:04:18 +01:00
|
|
|
else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
FT_TRACE5(( "sub top" ));
|
|
|
|
have_flag = 1;
|
|
|
|
}
|
2013-10-12 10:33:04 +02:00
|
|
|
|
2014-04-28 21:13:14 +02:00
|
|
|
if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
if ( have_flag )
|
|
|
|
FT_TRACE5(( ", " ));
|
|
|
|
FT_TRACE5(( "neutral" ));
|
|
|
|
have_flag = 1;
|
|
|
|
}
|
|
|
|
|
2013-10-19 21:46:03 +02:00
|
|
|
if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
|
2013-10-12 10:33:04 +02:00
|
|
|
{
|
|
|
|
if ( have_flag )
|
|
|
|
FT_TRACE5(( ", " ));
|
|
|
|
FT_TRACE5(( "small top" ));
|
|
|
|
have_flag = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( AF_LATIN_IS_LONG_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
if ( have_flag )
|
|
|
|
FT_TRACE5(( ", " ));
|
|
|
|
FT_TRACE5(( "long" ));
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_TRACE5(( ")" ));
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_TRACE5(( ":\n" ));
|
|
|
|
}
|
|
|
|
#endif /* FT_DEBUG_LEVEL_TRACE */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
num_flats = 0;
|
|
|
|
num_rounds = 0;
|
2015-11-08 08:37:51 +01:00
|
|
|
ascender = 0;
|
|
|
|
descender = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-08-25 08:37:47 +02:00
|
|
|
while ( *p )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2013-12-31 08:16:57 +01:00
|
|
|
FT_ULong glyph_index;
|
|
|
|
FT_Long y_offset;
|
2012-08-05 10:58:02 +02:00
|
|
|
FT_Int best_point, best_contour_first, best_contour_last;
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Vector* points;
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
|
|
|
|
FT_Pos best_y_extremum; /* same as points.y */
|
|
|
|
FT_Bool best_round = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
unsigned int i, num_idx;
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
const char* p_old;
|
|
|
|
FT_ULong ch;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
while ( *p == ' ' )
|
|
|
|
p++;
|
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
p_old = p;
|
|
|
|
GET_UTF8_CHAR( ch, p_old );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-11 08:08:48 +01:00
|
|
|
if ( !num_idx )
|
|
|
|
{
|
|
|
|
FT_TRACE5(( " U+%04lX unavailable\n", ch ));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
|
|
|
|
best_y_extremum = FT_INT_MIN;
|
|
|
|
else
|
|
|
|
best_y_extremum = FT_INT_MAX;
|
2013-08-25 08:37:47 +02:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
/* iterate over all glyph elements of the character cluster */
|
|
|
|
/* and get the data of the `biggest' one */
|
2015-12-06 18:18:02 +01:00
|
|
|
for ( i = 0; i < num_idx; i++ )
|
2013-08-25 13:07:08 +02:00
|
|
|
{
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
FT_Pos best_y;
|
|
|
|
FT_Bool round = 0;
|
|
|
|
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* load the character in the face -- skip unknown or empty ones */
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
glyph_index = af_shaper_get_elem( &metrics->root,
|
|
|
|
shaper_buf,
|
|
|
|
i,
|
|
|
|
NULL,
|
|
|
|
&y_offset );
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( glyph_index == 0 )
|
|
|
|
{
|
|
|
|
FT_TRACE5(( " U+%04lX unavailable\n", ch ));
|
|
|
|
continue;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
|
|
|
|
outline = face->glyph->outline;
|
|
|
|
/* reject glyphs that don't produce any rendering */
|
|
|
|
if ( error || outline.n_points <= 2 )
|
|
|
|
{
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
if ( num_idx == 1 )
|
|
|
|
FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch ));
|
|
|
|
else
|
|
|
|
FT_TRACE5(( " component %d of cluster starting with U+%04lX"
|
|
|
|
" contains no (usable) outlines\n", i, ch ));
|
|
|
|
#endif
|
2015-12-06 18:18:02 +01:00
|
|
|
continue;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* now compute min or max point indices and coordinates */
|
|
|
|
points = outline.points;
|
|
|
|
best_point = -1;
|
|
|
|
best_y = 0; /* make compiler happy */
|
|
|
|
best_contour_first = 0; /* ditto */
|
|
|
|
best_contour_last = 0; /* ditto */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
{
|
|
|
|
FT_Int nn;
|
|
|
|
FT_Int first = 0;
|
|
|
|
FT_Int last = -1;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
|
|
|
|
{
|
|
|
|
FT_Int old_best_point = best_point;
|
|
|
|
FT_Int pp;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-03-28 23:17:11 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
last = outline.contours[nn];
|
2004-03-27 09:43:17 +01:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
/* Avoid single-point contours since they are never */
|
|
|
|
/* rasterized. In some fonts, they correspond to mark */
|
|
|
|
/* attachment points that are way outside of the glyph's */
|
|
|
|
/* real outline. */
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( last <= first )
|
|
|
|
continue;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-09 20:04:18 +01:00
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bs ) ||
|
|
|
|
AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
|
2015-11-08 08:37:51 +01:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
for ( pp = first; pp <= last; pp++ )
|
2007-03-26 14:39:25 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( best_point < 0 || points[pp].y > best_y )
|
|
|
|
{
|
|
|
|
best_point = pp;
|
|
|
|
best_y = points[pp].y;
|
|
|
|
ascender = FT_MAX( ascender, best_y + y_offset );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
descender = FT_MIN( descender, points[pp].y + y_offset );
|
2007-03-26 14:39:25 +02:00
|
|
|
}
|
2015-11-08 08:37:51 +01:00
|
|
|
}
|
2015-12-06 18:18:02 +01:00
|
|
|
else
|
2015-11-08 08:37:51 +01:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
for ( pp = first; pp <= last; pp++ )
|
2007-03-26 14:39:25 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( best_point < 0 || points[pp].y < best_y )
|
|
|
|
{
|
|
|
|
best_point = pp;
|
|
|
|
best_y = points[pp].y;
|
|
|
|
descender = FT_MIN( descender, best_y + y_offset );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ascender = FT_MAX( ascender, points[pp].y + y_offset );
|
2007-03-26 14:39:25 +02:00
|
|
|
}
|
2015-11-08 08:37:51 +01:00
|
|
|
}
|
2007-03-26 14:39:25 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( best_point != old_best_point )
|
|
|
|
{
|
|
|
|
best_contour_first = first;
|
|
|
|
best_contour_last = last;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2007-03-26 14:39:25 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* now check whether the point belongs to a straight or round */
|
|
|
|
/* segment; we first need to find in which contour the extremum */
|
|
|
|
/* lies, then inspect its previous and next points */
|
|
|
|
if ( best_point >= 0 )
|
2012-08-05 11:11:44 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_Pos best_x = points[best_point].x;
|
|
|
|
FT_Int prev, next;
|
|
|
|
FT_Int best_segment_first, best_segment_last;
|
|
|
|
FT_Int best_on_point_first, best_on_point_last;
|
|
|
|
FT_Pos dist;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
best_segment_first = best_point;
|
|
|
|
best_segment_last = best_point;
|
2013-07-19 23:11:23 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
|
|
|
|
{
|
|
|
|
best_on_point_first = best_point;
|
|
|
|
best_on_point_last = best_point;
|
|
|
|
}
|
|
|
|
else
|
2012-08-05 11:11:44 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
best_on_point_first = -1;
|
|
|
|
best_on_point_last = -1;
|
2012-08-05 11:11:44 +02:00
|
|
|
}
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* look for the previous and next points on the contour */
|
|
|
|
/* that are not on the same Y coordinate, then threshold */
|
|
|
|
/* the `closeness'... */
|
|
|
|
prev = best_point;
|
|
|
|
next = prev;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if ( prev > best_contour_first )
|
|
|
|
prev--;
|
|
|
|
else
|
|
|
|
prev = best_contour_last;
|
|
|
|
|
|
|
|
dist = FT_ABS( points[prev].y - best_y );
|
|
|
|
/* accept a small distance or a small angle (both values are */
|
|
|
|
/* heuristic; value 20 corresponds to approx. 2.9 degrees) */
|
|
|
|
if ( dist > 5 )
|
|
|
|
if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
|
|
|
|
break;
|
|
|
|
|
|
|
|
best_segment_first = prev;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
|
|
|
|
{
|
|
|
|
best_on_point_first = prev;
|
|
|
|
if ( best_on_point_last < 0 )
|
|
|
|
best_on_point_last = prev;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
} while ( prev != best_point );
|
2013-07-19 23:11:23 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
do
|
2012-08-05 11:11:44 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( next < best_contour_last )
|
|
|
|
next++;
|
|
|
|
else
|
|
|
|
next = best_contour_first;
|
|
|
|
|
|
|
|
dist = FT_ABS( points[next].y - best_y );
|
|
|
|
if ( dist > 5 )
|
|
|
|
if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
|
|
|
|
break;
|
2012-08-05 11:11:44 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
best_segment_last = next;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
|
|
|
|
{
|
|
|
|
best_on_point_last = next;
|
|
|
|
if ( best_on_point_first < 0 )
|
|
|
|
best_on_point_first = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while ( next != best_point );
|
|
|
|
|
|
|
|
if ( AF_LATIN_IS_LONG_BLUE( bs ) )
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
/* If this flag is set, we have an additional constraint to */
|
|
|
|
/* get the blue zone distance: Find a segment of the topmost */
|
|
|
|
/* (or bottommost) contour that is longer than a heuristic */
|
|
|
|
/* threshold. This ensures that small bumps in the outline */
|
|
|
|
/* are ignored (for example, the `vertical serifs' found in */
|
|
|
|
/* many Hebrew glyph designs). */
|
|
|
|
|
|
|
|
/* If this segment is long enough, we are done. Otherwise, */
|
|
|
|
/* search the segment next to the extremum that is long */
|
|
|
|
/* enough, has the same direction, and a not too large */
|
|
|
|
/* vertical distance from the extremum. Note that the */
|
|
|
|
/* algorithm doesn't check whether the found segment is */
|
|
|
|
/* actually the one (vertically) nearest to the extremum. */
|
|
|
|
|
2013-09-11 23:08:31 +02:00
|
|
|
/* heuristic threshold value */
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_Pos length_threshold = metrics->units_per_em / 25;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
dist = FT_ABS( points[best_segment_last].x -
|
|
|
|
points[best_segment_first].x );
|
2014-06-17 09:14:32 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( dist < length_threshold &&
|
|
|
|
best_segment_last - best_segment_first + 2 <=
|
|
|
|
best_contour_last - best_contour_first )
|
|
|
|
{
|
|
|
|
/* heuristic threshold value */
|
|
|
|
FT_Pos height_threshold = metrics->units_per_em / 4;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_Int first;
|
|
|
|
FT_Int last;
|
|
|
|
FT_Bool hit;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* we intentionally declare these two variables */
|
|
|
|
/* outside of the loop since various compilers emit */
|
|
|
|
/* incorrect warning messages otherwise, talking about */
|
|
|
|
/* `possibly uninitialized variables' */
|
|
|
|
FT_Int p_first = 0; /* make compiler happy */
|
|
|
|
FT_Int p_last = 0;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_Bool left2right;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* compute direction */
|
|
|
|
prev = best_point;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if ( prev > best_contour_first )
|
|
|
|
prev--;
|
|
|
|
else
|
|
|
|
prev = best_contour_last;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( points[prev].x != best_x )
|
|
|
|
break;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
} while ( prev != best_point );
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* skip glyph for the degenerate case */
|
|
|
|
if ( prev == best_point )
|
|
|
|
continue;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
left2right = FT_BOOL( points[prev].x < points[best_point].x );
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
first = best_segment_last;
|
|
|
|
last = first;
|
|
|
|
hit = 0;
|
|
|
|
|
|
|
|
do
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_Bool l2r;
|
|
|
|
FT_Pos d;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
|
|
|
|
if ( !hit )
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
/* no hit; adjust first point */
|
|
|
|
first = last;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* also adjust first and last on point */
|
|
|
|
if ( FT_CURVE_TAG( outline.tags[first] ) ==
|
|
|
|
FT_CURVE_TAG_ON )
|
|
|
|
{
|
|
|
|
p_first = first;
|
|
|
|
p_last = first;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p_first = -1;
|
|
|
|
p_last = -1;
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
hit = 1;
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( last < best_contour_last )
|
|
|
|
last++;
|
|
|
|
else
|
|
|
|
last = best_contour_first;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( FT_ABS( best_y - points[first].y ) > height_threshold )
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
/* vertical distance too large */
|
2013-09-11 23:08:31 +02:00
|
|
|
hit = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* same test as above */
|
|
|
|
dist = FT_ABS( points[last].y - points[first].y );
|
|
|
|
if ( dist > 5 )
|
|
|
|
if ( FT_ABS( points[last].x - points[first].x ) <=
|
|
|
|
20 * dist )
|
|
|
|
{
|
|
|
|
hit = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
|
|
|
|
{
|
|
|
|
p_last = last;
|
|
|
|
if ( p_first < 0 )
|
|
|
|
p_first = last;
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
l2r = FT_BOOL( points[first].x < points[last].x );
|
|
|
|
d = FT_ABS( points[last].x - points[first].x );
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( l2r == left2right &&
|
|
|
|
d >= length_threshold )
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
/* all constraints are met; update segment after */
|
|
|
|
/* finding its end */
|
2015-12-06 18:18:02 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if ( last < best_contour_last )
|
|
|
|
last++;
|
|
|
|
else
|
|
|
|
last = best_contour_first;
|
|
|
|
|
|
|
|
d = FT_ABS( points[last].y - points[first].y );
|
|
|
|
if ( d > 5 )
|
|
|
|
if ( FT_ABS( points[next].x - points[first].x ) <=
|
|
|
|
20 * dist )
|
|
|
|
{
|
|
|
|
if ( last > best_contour_first )
|
|
|
|
last--;
|
|
|
|
else
|
|
|
|
last = best_contour_last;
|
|
|
|
break;
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
p_last = last;
|
|
|
|
|
|
|
|
if ( FT_CURVE_TAG( outline.tags[last] ) ==
|
|
|
|
FT_CURVE_TAG_ON )
|
2013-09-11 23:08:31 +02:00
|
|
|
{
|
2015-12-06 18:18:02 +01:00
|
|
|
p_last = last;
|
|
|
|
if ( p_first < 0 )
|
|
|
|
p_first = last;
|
2013-09-11 23:08:31 +02:00
|
|
|
}
|
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
} while ( last != best_segment_first );
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
best_y = points[first].y;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
best_segment_first = first;
|
|
|
|
best_segment_last = last;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
best_on_point_first = p_first;
|
|
|
|
best_on_point_last = p_last;
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
} while ( last != best_segment_first );
|
|
|
|
}
|
|
|
|
}
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
/* for computing blue zones, we add the y offset as returned */
|
|
|
|
/* by the currently used OpenType feature -- for example, */
|
|
|
|
/* superscript glyphs might be identical to subscript glyphs */
|
|
|
|
/* with a vertical shift */
|
|
|
|
best_y += y_offset;
|
|
|
|
|
2015-12-12 07:28:22 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
if ( num_idx == 1 )
|
|
|
|
FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
|
|
|
|
else
|
|
|
|
FT_TRACE5(( " component %d of cluster starting with U+%04lX:"
|
|
|
|
" best_y = %5ld", i, ch, best_y ));
|
|
|
|
#endif
|
2015-12-06 18:18:02 +01:00
|
|
|
|
|
|
|
/* now set the `round' flag depending on the segment's kind: */
|
|
|
|
/* */
|
|
|
|
/* - if the horizontal distance between the first and last */
|
|
|
|
/* `on' point is larger than a heuristic threshold */
|
|
|
|
/* we have a flat segment */
|
|
|
|
/* - if either the first or the last point of the segment is */
|
|
|
|
/* an `off' point, the segment is round, otherwise it is */
|
|
|
|
/* flat */
|
|
|
|
if ( best_on_point_first >= 0 &&
|
|
|
|
best_on_point_last >= 0 &&
|
|
|
|
( FT_ABS( points[best_on_point_last].x -
|
|
|
|
points[best_on_point_first].x ) ) >
|
|
|
|
flat_threshold )
|
|
|
|
round = 0;
|
|
|
|
else
|
|
|
|
round = FT_BOOL(
|
|
|
|
FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
|
|
|
|
FT_CURVE_TAG_ON ||
|
|
|
|
FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
|
|
|
|
FT_CURVE_TAG_ON );
|
2013-09-11 23:08:31 +02:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
/* only use flat segments for a neutral blue zone */
|
|
|
|
FT_TRACE5(( " (round, skipped)\n" ));
|
|
|
|
continue;
|
2013-09-11 23:08:31 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2015-12-06 18:18:02 +01:00
|
|
|
FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
|
2014-04-28 21:13:14 +02:00
|
|
|
}
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
|
|
|
|
{
|
|
|
|
if ( best_y > best_y_extremum )
|
|
|
|
{
|
|
|
|
best_y_extremum = best_y;
|
|
|
|
best_round = round;
|
|
|
|
}
|
|
|
|
}
|
2015-12-06 18:18:02 +01:00
|
|
|
else
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
{
|
|
|
|
if ( best_y < best_y_extremum )
|
|
|
|
{
|
|
|
|
best_y_extremum = best_y;
|
|
|
|
best_round = round;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* end for loop */
|
|
|
|
|
2015-12-09 21:00:33 +01:00
|
|
|
if ( !( best_y_extremum == FT_INT_MIN ||
|
|
|
|
best_y_extremum == FT_INT_MAX ) )
|
|
|
|
{
|
|
|
|
if ( best_round )
|
|
|
|
rounds[num_rounds++] = best_y_extremum;
|
|
|
|
else
|
|
|
|
flats[num_flats++] = best_y_extremum;
|
|
|
|
}
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
|
|
|
|
} /* end while loop */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( num_flats == 0 && num_rounds == 0 )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* we couldn't find a single glyph to compute this blue zone,
|
|
|
|
* we will simply ignore it then
|
|
|
|
*/
|
2012-07-04 13:00:06 +02:00
|
|
|
FT_TRACE5(( " empty\n" ));
|
2004-03-27 09:43:17 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have computed the contents of the `rounds' and `flats' tables, */
|
|
|
|
/* now determine the reference and overshoot position of the blue -- */
|
|
|
|
/* we simply take the median value after a simple sort */
|
|
|
|
af_sort_pos( num_rounds, rounds );
|
|
|
|
af_sort_pos( num_flats, flats );
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
blue = &axis->blues[axis->blue_count];
|
|
|
|
blue_ref = &blue->ref.org;
|
|
|
|
blue_shoot = &blue->shoot.org;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
axis->blue_count++;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( num_flats == 0 )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
*blue_ref =
|
2004-03-27 09:43:17 +01:00
|
|
|
*blue_shoot = rounds[num_rounds / 2];
|
|
|
|
}
|
|
|
|
else if ( num_rounds == 0 )
|
|
|
|
{
|
|
|
|
*blue_ref =
|
|
|
|
*blue_shoot = flats[num_flats / 2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-25 13:07:08 +02:00
|
|
|
*blue_ref = flats [num_flats / 2];
|
2004-03-27 09:43:17 +01:00
|
|
|
*blue_shoot = rounds[num_rounds / 2];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* there are sometimes problems: if the overshoot position of top */
|
|
|
|
/* zones is under its reference position, or the opposite for bottom */
|
|
|
|
/* zones. We must thus check everything there and correct the errors */
|
|
|
|
if ( *blue_shoot != *blue_ref )
|
|
|
|
{
|
|
|
|
FT_Pos ref = *blue_ref;
|
|
|
|
FT_Pos shoot = *blue_shoot;
|
|
|
|
FT_Bool over_ref = FT_BOOL( shoot > ref );
|
|
|
|
|
|
|
|
|
2015-12-09 20:04:18 +01:00
|
|
|
if ( ( AF_LATIN_IS_TOP_BLUE( bs ) ||
|
|
|
|
AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
|
2012-07-04 13:00:06 +02:00
|
|
|
{
|
2011-02-26 18:39:10 +01:00
|
|
|
*blue_ref =
|
|
|
|
*blue_shoot = ( shoot + ref ) / 2;
|
2012-07-04 13:00:06 +02:00
|
|
|
|
|
|
|
FT_TRACE5(( " [overshoot smaller than reference,"
|
|
|
|
" taking mean value]\n" ));
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2015-11-08 08:37:51 +01:00
|
|
|
blue->ascender = ascender;
|
|
|
|
blue->descender = descender;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
blue->flags = 0;
|
2013-08-25 08:37:47 +02:00
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
blue->flags |= AF_LATIN_BLUE_TOP;
|
2015-12-09 20:04:18 +01:00
|
|
|
if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
|
|
|
|
blue->flags |= AF_LATIN_BLUE_SUB_TOP;
|
2014-04-28 21:13:14 +02:00
|
|
|
if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
|
|
|
|
blue->flags |= AF_LATIN_BLUE_NEUTRAL;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
2009-04-27 19:40:35 +02:00
|
|
|
* The following flag is used later to adjust the y and x scales
|
2005-03-02 12:24:23 +01:00
|
|
|
* in order to optimize the pixel grid alignment of the top of small
|
|
|
|
* letters.
|
|
|
|
*/
|
2013-10-19 21:46:03 +02:00
|
|
|
if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
|
2004-06-04 19:41:59 +02:00
|
|
|
blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
|
|
|
|
|
2012-07-04 13:00:06 +02:00
|
|
|
FT_TRACE5(( " -> reference = %ld\n"
|
|
|
|
" overshoot = %ld\n",
|
|
|
|
*blue_ref, *blue_shoot ));
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
|
|
|
|
} /* end for loop */
|
|
|
|
|
|
|
|
af_shaper_buf_destroy( face, shaper_buf );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( "\n" ));
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Check whether all ASCII digits have the same advance width. */
|
|
|
|
|
2009-04-27 19:40:35 +02:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_latin_metrics_check_digits( AF_LatinMetrics metrics,
|
|
|
|
FT_Face face )
|
|
|
|
{
|
2009-11-15 10:17:44 +01:00
|
|
|
FT_Bool started = 0, same_width = 1;
|
|
|
|
FT_Fixed advance, old_advance = 0;
|
2009-04-27 19:40:35 +02:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
void* shaper_buf;
|
|
|
|
|
|
|
|
/* in all supported charmaps, digits have character codes 0x30-0x39 */
|
|
|
|
const char digits[] = "0 1 2 3 4 5 6 7 8 9";
|
|
|
|
const char* p;
|
|
|
|
|
2009-04-27 19:40:35 +02:00
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
p = digits;
|
|
|
|
shaper_buf = af_shaper_buf_create( face );
|
|
|
|
|
|
|
|
while ( *p )
|
2009-04-27 19:40:35 +02:00
|
|
|
{
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
FT_ULong glyph_index;
|
|
|
|
unsigned int num_idx;
|
2009-04-27 19:40:35 +02:00
|
|
|
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
/* reject input that maps to more than a single glyph */
|
|
|
|
p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
|
|
|
|
if ( num_idx > 1 )
|
2009-04-27 19:40:35 +02:00
|
|
|
continue;
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
glyph_index = af_shaper_get_elem( &metrics->root,
|
|
|
|
shaper_buf,
|
|
|
|
0,
|
|
|
|
&advance,
|
|
|
|
NULL );
|
|
|
|
if ( !glyph_index )
|
2009-04-27 19:40:35 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( started )
|
|
|
|
{
|
|
|
|
if ( advance != old_advance )
|
|
|
|
{
|
|
|
|
same_width = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
old_advance = advance;
|
|
|
|
started = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[autofit] Rewrite HarfBuzz interface to support character clusters.
Scripts like Khmer have blue zones that can't be directly
represented by Unicode characters. Instead, it is necessary to let
HarfBuzz convert character clusters into proper glyph representation
forms, then deriving the blue zone information from the resulting
glyphs.
* src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by...
* src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new
files, providing a new API to access HarfBuzz.
The new API manages a HarfBuzz buffer with `af_shaper_buf_create'
and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded
string with function `af_shaper_get_cluster', and the resulting
glyph data (indices, advance widths, vertical offsets) can be
iteratively accessed with function `af_shaper_get_elem'.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_check_digits):
Updated.
* include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/.
* src/autofit/afglobal.c: s/hbshim.h/afshaper.h/.
(af_face_globals_compute_style_coverage): Updated.
* src/autofit/afglocal.h: s/hbshim.h/afshaper.h/.
* src/autofit/autofit.c: s/hbshim.c/afshaper.c/.
* src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC):
Updated.
2015-12-06 18:52:41 +01:00
|
|
|
af_shaper_buf_destroy( face, shaper_buf );
|
|
|
|
|
2009-04-27 19:40:35 +02:00
|
|
|
metrics->root.digits_have_same_width = same_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Initialize global metrics. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
|
|
|
af_latin_metrics_init( AF_LatinMetrics metrics,
|
|
|
|
FT_Face face )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
FT_CharMap oldmap = face->charmap;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
metrics->units_per_em = face->units_per_EM;
|
|
|
|
|
2012-10-24 12:26:20 +02:00
|
|
|
if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
|
2005-03-06 11:17:28 +01:00
|
|
|
{
|
2012-10-24 14:22:14 +02:00
|
|
|
af_latin_metrics_init_widths( metrics, face );
|
2005-03-06 11:17:28 +01:00
|
|
|
af_latin_metrics_init_blues( metrics, face );
|
2009-04-27 19:40:35 +02:00
|
|
|
af_latin_metrics_check_digits( metrics, face );
|
2005-03-06 11:17:28 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
FT_Set_Charmap( face, oldmap );
|
2013-03-14 11:21:17 +01:00
|
|
|
return FT_Err_Ok;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Adjust scaling value, then scale and shift widths */
|
|
|
|
/* and blue zones (if applicable) for given dimension. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
2005-03-02 12:24:23 +01:00
|
|
|
af_latin_metrics_scale_dim( AF_LatinMetrics metrics,
|
|
|
|
AF_Scaler scaler,
|
|
|
|
AF_Dimension dim )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
FT_Fixed scale;
|
|
|
|
FT_Pos delta;
|
|
|
|
AF_LatinAxis axis;
|
|
|
|
FT_UInt nn;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
scale = scaler->x_scale;
|
|
|
|
delta = scaler->x_delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scale = scaler->y_scale;
|
|
|
|
delta = scaler->y_delta;
|
|
|
|
}
|
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
axis = &metrics->axis[dim];
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( axis->org_scale == scale && axis->org_delta == delta )
|
|
|
|
return;
|
|
|
|
|
|
|
|
axis->org_scale = scale;
|
|
|
|
axis->org_delta = delta;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* correct X and Y scale to optimize the alignment of the top of small
|
|
|
|
* letters to the pixel grid
|
|
|
|
*/
|
2004-06-04 19:41:59 +02:00
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_LatinBlue blue = NULL;
|
2004-06-04 19:41:59 +02:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
for ( nn = 0; nn < Axis->blue_count; nn++ )
|
2004-06-04 19:41:59 +02:00
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
|
2004-06-04 19:41:59 +02:00
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
blue = &Axis->blues[nn];
|
2004-06-04 19:41:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( blue )
|
|
|
|
{
|
2012-09-18 23:26:37 +02:00
|
|
|
FT_Pos scaled;
|
|
|
|
FT_Pos threshold;
|
|
|
|
FT_Pos fitted;
|
|
|
|
FT_UInt limit;
|
|
|
|
FT_UInt ppem;
|
|
|
|
|
|
|
|
|
|
|
|
scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
|
|
|
|
ppem = metrics->root.scaler.face->size->metrics.x_ppem;
|
|
|
|
limit = metrics->root.globals->increase_x_height;
|
|
|
|
threshold = 40;
|
|
|
|
|
2012-09-25 06:37:15 +02:00
|
|
|
/* if the `increase-x-height' property is active, */
|
2012-09-18 23:26:37 +02:00
|
|
|
/* we round up much more often */
|
|
|
|
if ( limit &&
|
|
|
|
ppem <= limit &&
|
|
|
|
ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN )
|
|
|
|
threshold = 52;
|
|
|
|
|
|
|
|
fitted = ( scaled + threshold ) & ~63;
|
2004-06-04 19:41:59 +02:00
|
|
|
|
|
|
|
if ( scaled != fitted )
|
|
|
|
{
|
2007-06-11 07:37:35 +02:00
|
|
|
#if 0
|
2004-06-04 19:41:59 +02:00
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
if ( fitted < scaled )
|
2007-03-06 12:59:24 +01:00
|
|
|
scale -= scale / 50; /* scale *= 0.98 */
|
2004-06-04 19:41:59 +02:00
|
|
|
}
|
|
|
|
else
|
2007-06-11 07:37:35 +02:00
|
|
|
#endif
|
|
|
|
if ( dim == AF_DIMENSION_VERT )
|
2013-10-12 10:33:04 +02:00
|
|
|
{
|
2015-11-08 08:37:51 +01:00
|
|
|
FT_Pos max_height;
|
|
|
|
FT_Pos dist;
|
|
|
|
FT_Fixed new_scale;
|
|
|
|
|
|
|
|
|
|
|
|
new_scale = FT_MulDiv( scale, fitted, scaled );
|
|
|
|
|
|
|
|
/* the scaling should not change the result by more than two pixels */
|
|
|
|
max_height = metrics->units_per_em;
|
|
|
|
|
|
|
|
for ( nn = 0; nn < Axis->blue_count; nn++ )
|
|
|
|
{
|
|
|
|
max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
|
|
|
|
max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
|
|
|
|
}
|
|
|
|
|
|
|
|
dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
|
|
|
|
dist &= ~127;
|
|
|
|
|
|
|
|
if ( dist == 0 )
|
|
|
|
{
|
|
|
|
scale = new_scale;
|
|
|
|
|
|
|
|
FT_TRACE5((
|
|
|
|
"af_latin_metrics_scale_dim:"
|
|
|
|
" x height alignment (style `%s'):\n"
|
|
|
|
" "
|
|
|
|
" vertical scaling changed from %.4f to %.4f (by %d%%)\n"
|
|
|
|
"\n",
|
|
|
|
af_style_names[metrics->root.style_class->style],
|
|
|
|
axis->org_scale / 65536.0,
|
|
|
|
scale / 65536.0,
|
|
|
|
( fitted - scaled ) * 100 / scaled ));
|
|
|
|
}
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FT_TRACE5((
|
|
|
|
"af_latin_metrics_scale_dim:"
|
|
|
|
" x height alignment (style `%s'):\n"
|
|
|
|
" "
|
|
|
|
" excessive vertical scaling abandoned\n"
|
|
|
|
"\n",
|
|
|
|
af_style_names[metrics->root.style_class->style] ));
|
|
|
|
}
|
|
|
|
#endif
|
2013-10-12 10:33:04 +02:00
|
|
|
}
|
2004-06-04 19:41:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
axis->scale = scale;
|
|
|
|
axis->delta = delta;
|
|
|
|
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
metrics->root.scaler.x_scale = scale;
|
|
|
|
metrics->root.scaler.x_delta = delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
metrics->root.scaler.y_scale = scale;
|
|
|
|
metrics->root.scaler.y_delta = delta;
|
|
|
|
}
|
|
|
|
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
FT_TRACE5(( "%s widths (style `%s')\n",
|
2013-10-12 10:33:04 +02:00
|
|
|
dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
af_style_names[metrics->root.style_class->style] ));
|
2013-10-12 10:33:04 +02:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* scale the widths */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( nn = 0; nn < axis->width_count; nn++ )
|
|
|
|
{
|
|
|
|
AF_Width width = axis->widths + nn;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
width->cur = FT_MulFix( width->org, scale );
|
|
|
|
width->fit = width->cur;
|
2013-10-12 10:33:04 +02:00
|
|
|
|
|
|
|
FT_TRACE5(( " %d scaled to %.2f\n",
|
|
|
|
width->org,
|
|
|
|
width->cur / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2013-10-12 10:33:04 +02:00
|
|
|
FT_TRACE5(( "\n" ));
|
|
|
|
|
2007-04-03 09:19:53 +02:00
|
|
|
/* an extra-light axis corresponds to a standard width that is */
|
2011-05-02 06:04:15 +02:00
|
|
|
/* smaller than 5/8 pixels */
|
2007-05-09 22:02:55 +02:00
|
|
|
axis->extra_light =
|
|
|
|
(FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
|
2007-04-02 15:13:54 +02:00
|
|
|
|
2013-10-12 10:33:04 +02:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
if ( axis->extra_light )
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
|
2013-10-16 19:47:57 +02:00
|
|
|
"\n",
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
af_style_names[metrics->root.style_class->style] ));
|
2013-10-12 10:33:04 +02:00
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( dim == AF_DIMENSION_VERT )
|
|
|
|
{
|
2015-09-26 16:57:17 +02:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
if ( axis->blue_count )
|
|
|
|
FT_TRACE5(( "blue zones (style `%s')\n",
|
|
|
|
af_style_names[metrics->root.style_class->style] ));
|
|
|
|
#endif
|
2013-10-12 10:33:04 +02:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* scale the blue zones */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( nn = 0; nn < axis->blue_count; nn++ )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_LatinBlue blue = &axis->blues[nn];
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Pos dist;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-06-04 19:41:59 +02:00
|
|
|
blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
|
|
|
|
blue->ref.fit = blue->ref.cur;
|
2004-03-27 09:43:17 +01:00
|
|
|
blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
|
|
|
|
blue->shoot.fit = blue->shoot.cur;
|
2004-06-04 19:41:59 +02:00
|
|
|
blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* a blue zone is only active if it is less than 3/4 pixels tall */
|
2004-03-27 09:43:17 +01:00
|
|
|
dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
|
2004-06-04 19:41:59 +02:00
|
|
|
if ( dist <= 48 && dist >= -48 )
|
|
|
|
{
|
2011-05-04 06:14:30 +02:00
|
|
|
#if 0
|
|
|
|
FT_Pos delta1;
|
|
|
|
#endif
|
|
|
|
FT_Pos delta2;
|
|
|
|
|
|
|
|
|
|
|
|
/* use discrete values for blue zone widths */
|
2004-06-04 19:41:59 +02:00
|
|
|
|
2011-05-04 06:14:30 +02:00
|
|
|
#if 0
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2011-05-04 06:14:30 +02:00
|
|
|
/* generic, original code */
|
2005-03-03 18:09:08 +01:00
|
|
|
delta1 = blue->shoot.org - blue->ref.org;
|
|
|
|
delta2 = delta1;
|
|
|
|
if ( delta1 < 0 )
|
2004-06-04 19:41:59 +02:00
|
|
|
delta2 = -delta2;
|
|
|
|
|
|
|
|
delta2 = FT_MulFix( delta2, scale );
|
|
|
|
|
|
|
|
if ( delta2 < 32 )
|
|
|
|
delta2 = 0;
|
|
|
|
else if ( delta2 < 64 )
|
|
|
|
delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
|
|
|
|
else
|
|
|
|
delta2 = FT_PIX_ROUND( delta2 );
|
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
if ( delta1 < 0 )
|
2004-06-04 19:41:59 +02:00
|
|
|
delta2 = -delta2;
|
|
|
|
|
2011-06-20 19:09:02 +02:00
|
|
|
blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
|
|
|
|
blue->shoot.fit = blue->ref.fit + delta2;
|
|
|
|
|
2011-05-04 06:14:30 +02:00
|
|
|
#else
|
|
|
|
|
|
|
|
/* simplified version due to abs(dist) <= 48 */
|
|
|
|
delta2 = dist;
|
|
|
|
if ( dist < 0 )
|
|
|
|
delta2 = -delta2;
|
|
|
|
|
|
|
|
if ( delta2 < 32 )
|
|
|
|
delta2 = 0;
|
2013-05-08 09:17:56 +02:00
|
|
|
else if ( delta2 < 48 )
|
2011-05-04 06:14:30 +02:00
|
|
|
delta2 = 32;
|
|
|
|
else
|
|
|
|
delta2 = 64;
|
|
|
|
|
|
|
|
if ( dist < 0 )
|
|
|
|
delta2 = -delta2;
|
|
|
|
|
2004-06-04 19:41:59 +02:00
|
|
|
blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
|
2011-06-20 19:09:02 +02:00
|
|
|
blue->shoot.fit = blue->ref.fit - delta2;
|
|
|
|
|
|
|
|
#endif
|
2004-06-04 19:41:59 +02:00
|
|
|
|
|
|
|
blue->flags |= AF_LATIN_BLUE_ACTIVE;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2015-12-09 14:45:30 +01:00
|
|
|
|
2015-12-09 20:04:18 +01:00
|
|
|
/* use sub-top blue zone only if it doesn't overlap with */
|
|
|
|
/* another (non-sup-top) blue zone; otherwise, the */
|
|
|
|
/* effect would be similar to a neutral blue zone, which */
|
|
|
|
/* is not desired here */
|
|
|
|
for ( nn = 0; nn < axis->blue_count; nn++ )
|
|
|
|
{
|
|
|
|
AF_LatinBlue blue = &axis->blues[nn];
|
|
|
|
FT_UInt i;
|
|
|
|
|
|
|
|
|
|
|
|
if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
|
|
|
|
continue;
|
|
|
|
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for ( i = 0; i < axis->blue_count; i++ )
|
|
|
|
{
|
|
|
|
AF_LatinBlue b = &axis->blues[i];
|
|
|
|
|
|
|
|
|
|
|
|
if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
|
|
|
|
continue;
|
|
|
|
if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( b->ref.fit <= blue->shoot.fit &&
|
|
|
|
b->shoot.fit >= blue->ref.fit )
|
|
|
|
{
|
|
|
|
blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-09 14:45:30 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
for ( nn = 0; nn < axis->blue_count; nn++ )
|
|
|
|
{
|
|
|
|
AF_LatinBlue blue = &axis->blues[nn];
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n"
|
|
|
|
" overshoot %d: %d scaled to %.2f%s\n",
|
|
|
|
nn,
|
|
|
|
blue->ref.org,
|
|
|
|
blue->ref.fit / 64.0,
|
|
|
|
blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
|
|
|
|
: " (inactive)",
|
|
|
|
nn,
|
|
|
|
blue->shoot.org,
|
|
|
|
blue->shoot.fit / 64.0,
|
|
|
|
blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
|
|
|
|
: " (inactive)" ));
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Scale global values in both directions. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_latin_metrics_scale( AF_LatinMetrics metrics,
|
|
|
|
AF_Scaler scaler )
|
|
|
|
{
|
2005-08-24 10:04:56 +02:00
|
|
|
metrics->root.scaler.render_mode = scaler->render_mode;
|
2006-03-21 17:30:04 +01:00
|
|
|
metrics->root.scaler.face = scaler->face;
|
2012-03-28 12:21:50 +02:00
|
|
|
metrics->root.scaler.flags = scaler->flags;
|
2005-08-24 10:04:56 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
|
|
|
|
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-02 09:32:26 +01:00
|
|
|
/* Extract standard_width from writing system/script specific */
|
|
|
|
/* metrics class. */
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_latin_get_standard_widths( AF_LatinMetrics metrics,
|
|
|
|
FT_Pos* stdHW,
|
|
|
|
FT_Pos* stdVW )
|
|
|
|
{
|
|
|
|
if ( stdHW )
|
|
|
|
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
|
|
|
|
|
|
|
|
if ( stdVW )
|
|
|
|
*stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** L A T I N G L Y P H A N A L Y S I S *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
|
|
|
|
/* Walk over all contours and compute its segments. */
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_hints_compute_segments( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
2015-08-05 21:53:50 +02:00
|
|
|
AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
|
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
|
|
|
FT_Memory memory = hints->memory;
|
|
|
|
FT_Error error = FT_Err_Ok;
|
|
|
|
AF_Segment segment = NULL;
|
|
|
|
AF_SegmentRec seg0;
|
|
|
|
AF_Point* contour = hints->contours;
|
|
|
|
AF_Point* contour_limit = contour + hints->num_contours;
|
|
|
|
AF_Direction major_dir, segment_dir;
|
|
|
|
|
|
|
|
FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
|
2004-03-27 09:43:17 +01: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
|
|
|
FT_ZERO( &seg0 );
|
|
|
|
seg0.score = 32000;
|
|
|
|
seg0.flags = AF_EDGE_NORMAL;
|
|
|
|
|
2005-03-03 18:09:08 +01:00
|
|
|
major_dir = (AF_Direction)FT_ABS( axis->major_dir );
|
2004-03-27 09:43:17 +01:00
|
|
|
segment_dir = major_dir;
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
axis->num_segments = 0;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* set up (u,v) in each point */
|
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
|
|
|
{
|
|
|
|
AF_Point point = hints->points;
|
|
|
|
AF_Point limit = point + hints->num_points;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( ; point < limit; point++ )
|
|
|
|
{
|
|
|
|
point->u = point->fx;
|
|
|
|
point->v = point->fy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AF_Point point = hints->points;
|
|
|
|
AF_Point limit = point + hints->num_points;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( ; point < limit; point++ )
|
|
|
|
{
|
|
|
|
point->u = point->fy;
|
|
|
|
point->v = point->fx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do each contour separately */
|
|
|
|
for ( ; contour < contour_limit; contour++ )
|
|
|
|
{
|
2015-08-05 21:53:50 +02:00
|
|
|
AF_Point point = contour[0];
|
|
|
|
AF_Point last = point->prev;
|
|
|
|
int on_edge = 0;
|
|
|
|
FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */
|
|
|
|
FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
|
|
|
|
FT_Pos min_on_pos = 32000;
|
|
|
|
FT_Pos max_on_pos = -32000;
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Bool passed;
|
|
|
|
|
|
|
|
|
|
|
|
if ( point == last ) /* skip singletons -- just in case */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( FT_ABS( last->out_dir ) == major_dir &&
|
|
|
|
FT_ABS( point->out_dir ) == major_dir )
|
|
|
|
{
|
|
|
|
/* we are already on an edge, try to locate its start */
|
|
|
|
last = point;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
point = point->prev;
|
|
|
|
if ( FT_ABS( point->out_dir ) != major_dir )
|
|
|
|
{
|
|
|
|
point = point->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( point == last )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
last = point;
|
|
|
|
passed = 0;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
FT_Pos u, v;
|
|
|
|
|
|
|
|
|
|
|
|
if ( on_edge )
|
|
|
|
{
|
|
|
|
u = point->u;
|
|
|
|
if ( u < min_pos )
|
|
|
|
min_pos = u;
|
|
|
|
if ( u > max_pos )
|
|
|
|
max_pos = u;
|
|
|
|
|
2015-08-05 21:53:50 +02:00
|
|
|
/* get minimum and maximum coordinate of on points */
|
|
|
|
if ( !( point->flags & AF_FLAG_CONTROL ) )
|
|
|
|
{
|
|
|
|
v = point->v;
|
|
|
|
if ( v < min_on_pos )
|
|
|
|
min_on_pos = v;
|
|
|
|
if ( v > max_on_pos )
|
|
|
|
max_on_pos = v;
|
|
|
|
}
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( point->out_dir != segment_dir || point == last )
|
|
|
|
{
|
|
|
|
/* we are just leaving an edge; record a new segment! */
|
|
|
|
segment->last = point;
|
2005-05-10 00:11:36 +02:00
|
|
|
segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
/* a segment is round if either its first or last point */
|
2015-08-05 21:53:50 +02:00
|
|
|
/* is a control point, and the length of the on points */
|
|
|
|
/* inbetween doesn't exceed a heuristic limit */
|
|
|
|
if ( ( segment->first->flags | point->flags ) & AF_FLAG_CONTROL &&
|
|
|
|
( max_on_pos - min_on_pos ) < flat_threshold )
|
2004-03-27 09:43:17 +01:00
|
|
|
segment->flags |= AF_EDGE_ROUND;
|
|
|
|
|
|
|
|
/* compute segment size */
|
|
|
|
min_pos = max_pos = point->v;
|
|
|
|
|
|
|
|
v = segment->first->v;
|
|
|
|
if ( v < min_pos )
|
|
|
|
min_pos = v;
|
|
|
|
if ( v > max_pos )
|
|
|
|
max_pos = v;
|
|
|
|
|
2005-05-10 00:11:36 +02:00
|
|
|
segment->min_coord = (FT_Short)min_pos;
|
|
|
|
segment->max_coord = (FT_Short)max_pos;
|
2007-01-17 13:45:26 +01:00
|
|
|
segment->height = (FT_Short)( segment->max_coord -
|
|
|
|
segment->min_coord );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
on_edge = 0;
|
2005-03-01 16:48:29 +01:00
|
|
|
segment = NULL;
|
2012-07-09 08:19:25 +02:00
|
|
|
/* fall through */
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now exit if we are at the start/end point */
|
|
|
|
if ( point == last )
|
|
|
|
{
|
|
|
|
if ( passed )
|
|
|
|
break;
|
|
|
|
passed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !on_edge && FT_ABS( point->out_dir ) == major_dir )
|
|
|
|
{
|
|
|
|
/* this is the start of a new segment! */
|
2005-03-03 18:09:08 +01:00
|
|
|
segment_dir = (AF_Direction)point->out_dir;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
error = af_axis_hints_new_segment( axis, memory, &segment );
|
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-09-22 08:38:00 +02:00
|
|
|
/* clear all segment fields */
|
|
|
|
segment[0] = seg0;
|
|
|
|
|
2015-08-05 21:53:50 +02:00
|
|
|
segment->dir = (FT_Char)segment_dir;
|
|
|
|
segment->first = point;
|
|
|
|
segment->last = point;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
min_pos = max_pos = point->u;
|
2015-08-05 21:53:50 +02:00
|
|
|
|
|
|
|
if ( point->flags & AF_FLAG_CONTROL )
|
|
|
|
{
|
|
|
|
min_on_pos = 32000;
|
|
|
|
max_on_pos = -32000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
min_on_pos = max_on_pos = point->v;
|
2014-09-22 08:38:00 +02:00
|
|
|
|
|
|
|
on_edge = 1;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
point = point->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* contours */
|
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
/* now slightly increase the height of segments if this makes */
|
|
|
|
/* sense -- this is used to better detect and ignore serifs */
|
2006-11-23 15:49:48 +01:00
|
|
|
{
|
2006-12-01 09:20:47 +01:00
|
|
|
AF_Segment segments = axis->segments;
|
2006-11-23 15:49:48 +01:00
|
|
|
AF_Segment segments_end = segments + axis->num_segments;
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
for ( segment = segments; segment < segments_end; segment++ )
|
|
|
|
{
|
2006-12-01 09:20:47 +01:00
|
|
|
AF_Point first = segment->first;
|
|
|
|
AF_Point last = segment->last;
|
2006-11-23 15:49:48 +01:00
|
|
|
FT_Pos first_v = first->v;
|
|
|
|
FT_Pos last_v = last->v;
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
if ( first_v < last_v )
|
|
|
|
{
|
|
|
|
AF_Point p;
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
p = first->prev;
|
|
|
|
if ( p->v < first_v )
|
2007-01-02 20:20:08 +01:00
|
|
|
segment->height = (FT_Short)( segment->height +
|
|
|
|
( ( first_v - p->v ) >> 1 ) );
|
2006-11-23 15:49:48 +01:00
|
|
|
|
|
|
|
p = last->next;
|
|
|
|
if ( p->v > last_v )
|
2007-01-02 20:20:08 +01:00
|
|
|
segment->height = (FT_Short)( segment->height +
|
|
|
|
( ( p->v - last_v ) >> 1 ) );
|
2006-11-23 15:49:48 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AF_Point p;
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
p = first->prev;
|
|
|
|
if ( p->v > first_v )
|
2007-01-02 20:20:08 +01:00
|
|
|
segment->height = (FT_Short)( segment->height +
|
|
|
|
( ( p->v - first_v ) >> 1 ) );
|
2006-11-23 15:49:48 +01:00
|
|
|
|
|
|
|
p = last->next;
|
|
|
|
if ( p->v < last_v )
|
2007-01-02 20:20:08 +01:00
|
|
|
segment->height = (FT_Short)( segment->height +
|
|
|
|
( ( last_v - p->v ) >> 1 ) );
|
2006-11-23 15:49:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
Exit:
|
|
|
|
return error;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-05 16:27:19 +02:00
|
|
|
/* Link segments to form stems and serifs. If `width_count' and */
|
|
|
|
/* `widths' are non-zero, use them to fine-tune the scoring function. */
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_LOCAL_DEF( void )
|
|
|
|
af_latin_hints_link_segments( AF_GlyphHints hints,
|
2014-04-05 16:27:19 +02:00
|
|
|
FT_UInt width_count,
|
|
|
|
AF_WidthRec* widths,
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
|
|
|
AF_Segment segments = axis->segments;
|
|
|
|
AF_Segment segment_limit = segments + axis->num_segments;
|
2014-04-05 16:27:19 +02:00
|
|
|
FT_Pos len_threshold, len_score, dist_score, max_width;
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Segment seg1, seg2;
|
|
|
|
|
2005-09-23 10:00:51 +02:00
|
|
|
|
2014-04-05 16:27:19 +02:00
|
|
|
if ( width_count )
|
|
|
|
max_width = widths[width_count - 1].org;
|
|
|
|
else
|
|
|
|
max_width = 0;
|
|
|
|
|
|
|
|
/* a heuristic value to set up a minimum value for overlapping */
|
2006-02-11 13:12:02 +01:00
|
|
|
len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
|
|
|
|
if ( len_threshold == 0 )
|
|
|
|
len_threshold = 1;
|
|
|
|
|
2014-04-05 00:08:52 +02:00
|
|
|
/* a heuristic value to weight lengths */
|
2006-11-23 15:49:48 +01:00
|
|
|
len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
|
2006-02-09 15:17:04 +01:00
|
|
|
|
2014-04-05 16:27:19 +02:00
|
|
|
/* a heuristic value to weight distances (no call to */
|
|
|
|
/* AF_LATIN_CONSTANT needed, since we work on multiples */
|
|
|
|
/* of the stem width) */
|
|
|
|
dist_score = 3000;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* now compare each segment to the others */
|
|
|
|
for ( seg1 = segments; seg1 < segment_limit; seg1++ )
|
|
|
|
{
|
2014-09-24 19:06:13 +02:00
|
|
|
if ( seg1->dir != axis->major_dir )
|
2004-03-27 09:43:17 +01:00
|
|
|
continue;
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* search for stems having opposite directions, */
|
|
|
|
/* with seg1 to the `left' of seg2 */
|
2007-06-11 21:36:48 +02:00
|
|
|
for ( seg2 = segments; seg2 < segment_limit; seg2++ )
|
2011-02-26 18:36:21 +01:00
|
|
|
{
|
|
|
|
FT_Pos pos1 = seg1->pos;
|
|
|
|
FT_Pos pos2 = seg2->pos;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-02-26 18:36:21 +01:00
|
|
|
if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
|
|
|
|
{
|
2011-02-26 18:39:10 +01:00
|
|
|
/* compute distance between the two segments */
|
2014-04-05 16:27:19 +02:00
|
|
|
FT_Pos min = seg1->min_coord;
|
|
|
|
FT_Pos max = seg1->max_coord;
|
|
|
|
FT_Pos len;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2011-02-26 18:36:21 +01:00
|
|
|
if ( min < seg2->min_coord )
|
|
|
|
min = seg2->min_coord;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:36:21 +01:00
|
|
|
if ( max > seg2->max_coord )
|
|
|
|
max = seg2->max_coord;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* compute maximum coordinate difference of the two segments */
|
2014-04-05 00:08:52 +02:00
|
|
|
/* (this is, how much they overlap) */
|
2011-02-26 18:36:21 +01:00
|
|
|
len = max - min;
|
|
|
|
if ( len >= len_threshold )
|
|
|
|
{
|
2014-04-05 16:27:19 +02:00
|
|
|
/*
|
|
|
|
* The score is the sum of two demerits indicating the
|
|
|
|
* `badness' of a fit, measured along the segments' main axis
|
|
|
|
* and orthogonal to it, respectively.
|
|
|
|
*
|
|
|
|
* o The less overlapping along the main axis, the worse it
|
|
|
|
* is, causing a larger demerit.
|
|
|
|
*
|
|
|
|
* o The nearer the orthogonal distance to a stem width, the
|
|
|
|
* better it is, causing a smaller demerit. For simplicity,
|
|
|
|
* however, we only increase the demerit for values that
|
|
|
|
* exceed the largest stem width.
|
|
|
|
*/
|
|
|
|
|
|
|
|
FT_Pos dist = pos2 - pos1;
|
|
|
|
|
|
|
|
FT_Pos dist_demerit, score;
|
|
|
|
|
|
|
|
|
|
|
|
if ( max_width )
|
|
|
|
{
|
|
|
|
/* distance demerits are based on multiples of `max_width'; */
|
|
|
|
/* we scale by 1024 for getting more precision */
|
|
|
|
FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
|
|
|
|
|
|
|
|
|
|
|
|
if ( delta > 10000 )
|
|
|
|
dist_demerit = 32000;
|
|
|
|
else if ( delta > 0 )
|
|
|
|
dist_demerit = delta * delta / dist_score;
|
|
|
|
else
|
|
|
|
dist_demerit = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dist_demerit = dist; /* default if no widths available */
|
|
|
|
|
|
|
|
score = dist_demerit + len_score / len;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* and we search for the smallest score */
|
2011-02-26 18:36:21 +01:00
|
|
|
if ( score < seg1->score )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2011-02-26 18:36:21 +01:00
|
|
|
seg1->score = score;
|
|
|
|
seg1->link = seg2;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:36:21 +01:00
|
|
|
if ( score < seg2->score )
|
|
|
|
{
|
|
|
|
seg2->score = score;
|
|
|
|
seg2->link = seg1;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-26 18:36:21 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* now compute the `serif' segments, cf. explanations in `afhints.h' */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( seg1 = segments; seg1 < segment_limit; seg1++ )
|
|
|
|
{
|
|
|
|
seg2 = seg1->link;
|
|
|
|
|
|
|
|
if ( seg2 )
|
|
|
|
{
|
|
|
|
if ( seg2->link != seg1 )
|
|
|
|
{
|
|
|
|
seg1->link = 0;
|
|
|
|
seg1->serif = seg2->link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Link segments to edges, using feature analysis for selection. */
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_hints_compute_edges( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
2013-03-14 11:21:17 +01:00
|
|
|
FT_Error error = FT_Err_Ok;
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Memory memory = hints->memory;
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_Segment segments = axis->segments;
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Segment segment_limit = segments + axis->num_segments;
|
|
|
|
AF_Segment seg;
|
|
|
|
|
2011-05-30 07:20:37 +02:00
|
|
|
#if 0
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Direction up_dir;
|
2011-05-30 07:20:37 +02:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Fixed scale;
|
|
|
|
FT_Pos edge_distance_threshold;
|
2006-11-03 00:28:09 +01:00
|
|
|
FT_Pos segment_length_threshold;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
axis->num_edges = 0;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
|
|
|
|
: hints->y_scale;
|
|
|
|
|
2011-05-30 07:20:37 +02:00
|
|
|
#if 0
|
2004-03-27 09:43:17 +01:00
|
|
|
up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
|
|
|
|
: AF_DIR_RIGHT;
|
2011-05-30 07:20:37 +02:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
/*
|
2011-02-26 18:39:10 +01:00
|
|
|
* We ignore all segments that are less than 1 pixel in length
|
2006-11-03 10:40:12 +01:00
|
|
|
* to avoid many problems with serif fonts. We compute the
|
|
|
|
* corresponding threshold in font units.
|
2006-11-03 00:28:09 +01:00
|
|
|
*/
|
2006-11-10 17:49:42 +01:00
|
|
|
if ( dim == AF_DIMENSION_HORZ )
|
2007-02-12 23:33:48 +01:00
|
|
|
segment_length_threshold = FT_DivFix( 64, hints->y_scale );
|
2006-11-03 00:28:09 +01:00
|
|
|
else
|
|
|
|
segment_length_threshold = 0;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/*********************************************************************/
|
|
|
|
/* */
|
2011-02-26 18:39:10 +01:00
|
|
|
/* We begin by generating a sorted table of edges for the current */
|
|
|
|
/* direction. To do so, we simply scan each segment and try to find */
|
|
|
|
/* an edge in our table that corresponds to its position. */
|
2004-03-27 09:43:17 +01:00
|
|
|
/* */
|
|
|
|
/* If no edge is found, we create and insert a new edge in the */
|
|
|
|
/* sorted table. Otherwise, we simply add the segment to the edge's */
|
2011-02-26 18:39:10 +01:00
|
|
|
/* list which gets processed in the second step to compute the */
|
2004-03-27 09:43:17 +01:00
|
|
|
/* edge's properties. */
|
|
|
|
/* */
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Note that the table of edges is sorted along the segment/edge */
|
2004-03-27 09:43:17 +01:00
|
|
|
/* position. */
|
|
|
|
/* */
|
|
|
|
/*********************************************************************/
|
|
|
|
|
2011-05-02 06:04:15 +02:00
|
|
|
/* assure that edge distance threshold is at most 0.25px */
|
2004-06-04 19:41:59 +02:00
|
|
|
edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
|
2004-03-27 09:43:17 +01:00
|
|
|
scale );
|
|
|
|
if ( edge_distance_threshold > 64 / 4 )
|
|
|
|
edge_distance_threshold = 64 / 4;
|
|
|
|
|
|
|
|
edge_distance_threshold = FT_DivFix( edge_distance_threshold,
|
|
|
|
scale );
|
|
|
|
|
|
|
|
for ( seg = segments; seg < segment_limit; seg++ )
|
|
|
|
{
|
2011-02-26 18:39:10 +01:00
|
|
|
AF_Edge found = NULL;
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Int ee;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
if ( seg->height < segment_length_threshold )
|
2006-11-03 00:28:09 +01:00
|
|
|
continue;
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2007-02-16 09:10:17 +01:00
|
|
|
/* A special case for serif edges: If they are smaller than */
|
|
|
|
/* 1.5 pixels we ignore them. */
|
|
|
|
if ( seg->serif &&
|
|
|
|
2 * seg->height < 3 * segment_length_threshold )
|
2007-02-12 23:33:48 +01:00
|
|
|
continue;
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* look for an edge corresponding to the segment */
|
2005-03-01 16:48:29 +01:00
|
|
|
for ( ee = 0; ee < axis->num_edges; ee++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
AF_Edge edge = axis->edges + ee;
|
|
|
|
FT_Pos dist;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
dist = seg->pos - edge->fpos;
|
|
|
|
if ( dist < 0 )
|
|
|
|
dist = -dist;
|
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
if ( dist < edge_distance_threshold && edge->dir == seg->dir )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
found = edge;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !found )
|
|
|
|
{
|
2007-07-07 09:30:40 +02:00
|
|
|
AF_Edge edge;
|
2005-03-01 16:48:29 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* insert a new edge in the list and */
|
|
|
|
/* sort according to the position */
|
2007-07-07 09:30:40 +02:00
|
|
|
error = af_axis_hints_new_edge( axis, seg->pos,
|
|
|
|
(AF_Direction)seg->dir,
|
|
|
|
memory, &edge );
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
/* add the segment to the new edge's list */
|
2005-03-02 12:24:23 +01:00
|
|
|
FT_ZERO( edge );
|
2005-03-01 16:48:29 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->first = seg;
|
|
|
|
edge->last = seg;
|
2007-06-11 07:37:35 +02:00
|
|
|
edge->dir = seg->dir;
|
2011-02-26 18:39:10 +01:00
|
|
|
edge->fpos = seg->pos;
|
|
|
|
edge->opos = FT_MulFix( seg->pos, scale );
|
|
|
|
edge->pos = edge->opos;
|
2004-03-27 09:43:17 +01:00
|
|
|
seg->edge_next = seg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* if an edge was found, simply add the segment to the edge's */
|
|
|
|
/* list */
|
2005-03-01 16:48:29 +01:00
|
|
|
seg->edge_next = found->first;
|
|
|
|
found->last->edge_next = seg;
|
|
|
|
found->last = seg;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
/******************************************************************/
|
|
|
|
/* */
|
|
|
|
/* Good, we now compute each edge's properties according to the */
|
|
|
|
/* segments found on its position. Basically, these are */
|
|
|
|
/* */
|
|
|
|
/* - the edge's main direction */
|
|
|
|
/* - stem edge, serif edge or both (which defaults to stem then) */
|
|
|
|
/* - rounded edge, straight or both (which defaults to straight) */
|
|
|
|
/* - link for edge */
|
|
|
|
/* */
|
|
|
|
/******************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
/* first of all, set the `edge' field in each segment -- this is */
|
|
|
|
/* required in order to compute edge links */
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* Note that removing this loop and setting the `edge' field of each
|
|
|
|
* segment directly in the code above slows down execution speed for
|
|
|
|
* some reasons on platforms like the Sun.
|
2004-03-27 09:43:17 +01:00
|
|
|
*/
|
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
AF_Edge edges = axis->edges;
|
|
|
|
AF_Edge edge_limit = edges + axis->num_edges;
|
|
|
|
AF_Edge edge;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
for ( edge = edges; edge < edge_limit; edge++ )
|
|
|
|
{
|
|
|
|
seg = edge->first;
|
|
|
|
if ( seg )
|
|
|
|
do
|
|
|
|
{
|
|
|
|
seg->edge = edge;
|
|
|
|
seg = seg->edge_next;
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
} while ( seg != edge->first );
|
2005-03-01 16:48:29 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* now compute each edge properties */
|
2005-03-01 16:48:29 +01:00
|
|
|
for ( edge = edges; edge < edge_limit; edge++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Int is_round = 0; /* does it contain round segments? */
|
|
|
|
FT_Int is_straight = 0; /* does it contain straight segments? */
|
2011-02-24 05:52:14 +01:00
|
|
|
#if 0
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Pos ups = 0; /* number of upwards segments */
|
|
|
|
FT_Pos downs = 0; /* number of downwards segments */
|
2011-02-24 05:52:14 +01:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
seg = edge->first;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
FT_Bool is_serif;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
/* check for roundness of segment */
|
|
|
|
if ( seg->flags & AF_EDGE_ROUND )
|
|
|
|
is_round++;
|
|
|
|
else
|
|
|
|
is_straight++;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-24 05:52:14 +01:00
|
|
|
#if 0
|
2005-03-01 16:48:29 +01:00
|
|
|
/* check for segment direction */
|
|
|
|
if ( seg->dir == up_dir )
|
2011-02-26 18:39:10 +01:00
|
|
|
ups += seg->max_coord - seg->min_coord;
|
2005-03-01 16:48:29 +01:00
|
|
|
else
|
2011-02-26 18:39:10 +01:00
|
|
|
downs += seg->max_coord - seg->min_coord;
|
2011-02-24 05:52:14 +01:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
/* check for links -- if seg->serif is set, then seg->link must */
|
|
|
|
/* be ignored */
|
2006-11-03 10:40:12 +01:00
|
|
|
is_serif = (FT_Bool)( seg->serif &&
|
|
|
|
seg->serif->edge &&
|
2006-11-03 00:28:09 +01:00
|
|
|
seg->serif->edge != edge );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
AF_Edge edge2;
|
|
|
|
AF_Segment seg2;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
edge2 = edge->link;
|
|
|
|
seg2 = seg->link;
|
|
|
|
|
|
|
|
if ( is_serif )
|
|
|
|
{
|
|
|
|
seg2 = seg->serif;
|
|
|
|
edge2 = edge->serif;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( edge2 )
|
|
|
|
{
|
|
|
|
FT_Pos edge_delta;
|
|
|
|
FT_Pos seg_delta;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
edge_delta = edge->fpos - edge2->fpos;
|
|
|
|
if ( edge_delta < 0 )
|
|
|
|
edge_delta = -edge_delta;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
seg_delta = seg->pos - seg2->pos;
|
|
|
|
if ( seg_delta < 0 )
|
|
|
|
seg_delta = -seg_delta;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( seg_delta < edge_delta )
|
|
|
|
edge2 = seg2->edge;
|
|
|
|
}
|
|
|
|
else
|
2004-03-27 09:43:17 +01:00
|
|
|
edge2 = seg2->edge;
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( is_serif )
|
|
|
|
{
|
|
|
|
edge->serif = edge2;
|
|
|
|
edge2->flags |= AF_EDGE_SERIF;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
edge->link = edge2;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
seg = seg->edge_next;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
} while ( seg != edge->first );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
/* set the round/straight flags */
|
|
|
|
edge->flags = AF_EDGE_NORMAL;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( is_round > 0 && is_round >= is_straight )
|
|
|
|
edge->flags |= AF_EDGE_ROUND;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2007-06-11 07:37:35 +02:00
|
|
|
#if 0
|
2005-03-01 16:48:29 +01:00
|
|
|
/* set the edge's main direction */
|
|
|
|
edge->dir = AF_DIR_NONE;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( ups > downs )
|
2005-05-10 00:11:36 +02:00
|
|
|
edge->dir = (FT_Char)up_dir;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
else if ( ups < downs )
|
2005-05-10 00:11:36 +02:00
|
|
|
edge->dir = (FT_Char)-up_dir;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
else if ( ups == downs )
|
|
|
|
edge->dir = 0; /* both up and down! */
|
2007-06-11 07:37:35 +02:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* get rid of serifs if link is set */
|
2005-03-01 16:48:29 +01:00
|
|
|
/* XXX: This gets rid of many unpleasant artefacts! */
|
|
|
|
/* Example: the `c' in cour.pfa at size 13 */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( edge->serif && edge->link )
|
2015-04-14 04:40:17 +02:00
|
|
|
edge->serif = NULL;
|
2005-03-01 16:48:29 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2005-03-01 16:48:29 +01:00
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Detect segments and edges for given dimension. */
|
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_LOCAL_DEF( FT_Error )
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_hints_detect_features( AF_GlyphHints hints,
|
2014-04-05 16:27:19 +02:00
|
|
|
FT_UInt width_count,
|
|
|
|
AF_WidthRec* widths,
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Dimension dim )
|
|
|
|
{
|
2005-03-01 16:48:29 +01:00
|
|
|
FT_Error error;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
error = af_latin_hints_compute_segments( hints, dim );
|
|
|
|
if ( !error )
|
|
|
|
{
|
2014-04-05 16:27:19 +02:00
|
|
|
af_latin_hints_link_segments( hints, width_count, widths, dim );
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
error = af_latin_hints_compute_edges( hints, dim );
|
2005-03-01 16:48:29 +01:00
|
|
|
}
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2005-03-01 16:48:29 +01:00
|
|
|
return error;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Compute all edges which lie within blue zones. */
|
|
|
|
|
2015-03-01 19:27:09 +01:00
|
|
|
static void
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_hints_compute_blue_edges( AF_GlyphHints hints,
|
|
|
|
AF_LatinMetrics metrics )
|
|
|
|
{
|
2011-04-02 07:15:33 +02:00
|
|
|
AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Edge edge = axis->edges;
|
|
|
|
AF_Edge edge_limit = edge + axis->num_edges;
|
2011-04-02 07:15:33 +02:00
|
|
|
AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Fixed scale = latin->scale;
|
|
|
|
|
|
|
|
|
|
|
|
/* compute which blue zones are active, i.e. have their scaled */
|
|
|
|
/* size < 3/4 pixels */
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* for each horizontal edge search the blue zone which is closest */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( ; edge < edge_limit; edge++ )
|
|
|
|
{
|
2012-11-12 11:01:07 +01:00
|
|
|
FT_UInt bb;
|
2014-05-01 07:16:05 +02:00
|
|
|
AF_Width best_blue = NULL;
|
|
|
|
FT_Bool best_blue_is_neutral = 0;
|
|
|
|
FT_Pos best_dist; /* initial threshold */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* compute the initial threshold as a fraction of the EM size */
|
2011-02-26 18:39:10 +01:00
|
|
|
/* (the value 40 is heuristic) */
|
2004-03-27 09:43:17 +01:00
|
|
|
best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
|
|
|
|
|
2011-04-02 07:15:33 +02:00
|
|
|
/* assure a minimum distance of 0.5px */
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( best_dist > 64 / 2 )
|
|
|
|
best_dist = 64 / 2;
|
|
|
|
|
2012-11-12 11:01:07 +01:00
|
|
|
for ( bb = 0; bb < latin->blue_count; bb++ )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
AF_LatinBlue blue = latin->blues + bb;
|
2014-05-01 07:16:05 +02:00
|
|
|
FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* skip inactive blue zones (i.e., those that are too large) */
|
2005-03-02 12:24:23 +01:00
|
|
|
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
continue;
|
|
|
|
|
2014-04-28 21:13:14 +02:00
|
|
|
/* if it is a top zone, check for right edges (against the major */
|
|
|
|
/* direction); if it is a bottom zone, check for left edges (in */
|
|
|
|
/* the major direction) -- this assumes the TrueType convention */
|
|
|
|
/* for the orientation of contours */
|
2014-05-01 07:16:05 +02:00
|
|
|
is_top_blue =
|
2015-12-09 20:04:18 +01:00
|
|
|
(FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP |
|
|
|
|
AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
|
2014-05-01 07:16:05 +02:00
|
|
|
is_neutral_blue =
|
|
|
|
(FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
|
|
|
|
is_major_dir =
|
|
|
|
FT_BOOL( edge->dir == axis->major_dir );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-28 21:13:14 +02:00
|
|
|
/* neutral blue zones are handled for both directions */
|
2014-05-01 07:16:05 +02:00
|
|
|
if ( is_top_blue ^ is_major_dir || is_neutral_blue )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
FT_Pos dist;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* first of all, compare it to the reference position */
|
|
|
|
dist = edge->fpos - blue->ref.org;
|
|
|
|
if ( dist < 0 )
|
|
|
|
dist = -dist;
|
|
|
|
|
|
|
|
dist = FT_MulFix( dist, scale );
|
|
|
|
if ( dist < best_dist )
|
|
|
|
{
|
2014-05-01 07:16:05 +02:00
|
|
|
best_dist = dist;
|
|
|
|
best_blue = &blue->ref;
|
|
|
|
best_blue_is_neutral = is_neutral_blue;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* now compare it to the overshoot position and check whether */
|
|
|
|
/* the edge is rounded, and whether the edge is over the */
|
|
|
|
/* reference position of a top zone, or under the reference */
|
2014-04-28 21:13:14 +02:00
|
|
|
/* position of a bottom zone (provided we don't have a */
|
|
|
|
/* neutral blue zone) */
|
2014-05-01 07:16:05 +02:00
|
|
|
if ( edge->flags & AF_EDGE_ROUND &&
|
|
|
|
dist != 0 &&
|
|
|
|
!is_neutral_blue )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
|
|
|
|
|
|
|
|
|
|
|
|
if ( is_top_blue ^ is_under_ref )
|
|
|
|
{
|
|
|
|
dist = edge->fpos - blue->shoot.org;
|
|
|
|
if ( dist < 0 )
|
|
|
|
dist = -dist;
|
|
|
|
|
|
|
|
dist = FT_MulFix( dist, scale );
|
|
|
|
if ( dist < best_dist )
|
|
|
|
{
|
2014-05-01 07:16:05 +02:00
|
|
|
best_dist = dist;
|
|
|
|
best_blue = &blue->shoot;
|
|
|
|
best_blue_is_neutral = is_neutral_blue;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( best_blue )
|
2014-05-01 07:16:05 +02:00
|
|
|
{
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->blue_edge = best_blue;
|
2014-05-01 07:16:05 +02:00
|
|
|
if ( best_blue_is_neutral )
|
|
|
|
edge->flags |= AF_EDGE_NEUTRAL;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Initalize hinting engine. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static FT_Error
|
|
|
|
af_latin_hints_init( AF_GlyphHints hints,
|
|
|
|
AF_LatinMetrics metrics )
|
|
|
|
{
|
|
|
|
FT_Render_Mode mode;
|
2005-12-14 17:37:15 +01:00
|
|
|
FT_UInt32 scaler_flags, other_flags;
|
2006-03-20 17:01:28 +01:00
|
|
|
FT_Face face = metrics->root.scaler.face;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2013-12-18 12:59:35 +01:00
|
|
|
af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
2007-01-25 12:50:00 +01:00
|
|
|
* correct x_scale and y_scale if needed, since they may have
|
2011-02-26 18:39:10 +01:00
|
|
|
* been modified by `af_latin_metrics_scale_dim' above
|
2005-03-02 12:24:23 +01:00
|
|
|
*/
|
|
|
|
hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
|
|
|
|
hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
|
|
|
|
hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
|
|
|
|
hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-12-20 13:01:58 +01:00
|
|
|
/* compute flags depending on render mode, etc. */
|
2004-03-27 09:43:17 +01:00
|
|
|
mode = metrics->root.scaler.render_mode;
|
|
|
|
|
2011-03-02 03:52:36 +01:00
|
|
|
#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
|
2006-01-21 15:31:45 +01:00
|
|
|
if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
|
|
|
|
metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
|
|
|
|
#endif
|
|
|
|
|
2005-12-14 17:37:15 +01:00
|
|
|
scaler_flags = hints->scaler_flags;
|
|
|
|
other_flags = 0;
|
2005-09-23 10:00:51 +02:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* We snap the width of vertical stems for the monochrome and
|
|
|
|
* horizontal LCD rendering targets only.
|
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
|
2005-12-14 17:37:15 +01:00
|
|
|
other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* We snap the width of horizontal stems for the monochrome and
|
|
|
|
* vertical LCD rendering targets only.
|
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
|
2005-12-14 17:37:15 +01:00
|
|
|
other_flags |= AF_LATIN_HINTS_VERT_SNAP;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* We adjust stems to full pixels only if we don't use the `light' mode.
|
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( mode != FT_RENDER_MODE_LIGHT )
|
2005-12-14 17:37:15 +01:00
|
|
|
other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( mode == FT_RENDER_MODE_MONO )
|
2005-12-14 17:37:15 +01:00
|
|
|
other_flags |= AF_LATIN_HINTS_MONO;
|
|
|
|
|
2005-12-20 13:01:58 +01:00
|
|
|
/*
|
|
|
|
* In `light' hinting mode we disable horizontal hinting completely.
|
2006-03-20 17:55:32 +01:00
|
|
|
* We also do it if the face is italic.
|
2015-04-16 20:11:49 +02:00
|
|
|
*
|
|
|
|
* However, if warping is enabled (which only works in `light' hinting
|
|
|
|
* mode), advance widths get adjusted, too.
|
2005-12-14 17:37:15 +01:00
|
|
|
*/
|
2011-02-26 18:39:10 +01:00
|
|
|
if ( mode == FT_RENDER_MODE_LIGHT ||
|
|
|
|
( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
|
2005-12-14 17:37:15 +01:00
|
|
|
scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
|
|
|
|
|
2015-04-21 07:13:59 +02:00
|
|
|
#ifdef AF_CONFIG_OPTION_USE_WARPER
|
|
|
|
/* get (global) warper flag */
|
|
|
|
if ( !metrics->root.globals->module->warping )
|
|
|
|
scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
|
|
|
|
#endif
|
|
|
|
|
2005-12-14 17:37:15 +01:00
|
|
|
hints->scaler_flags = scaler_flags;
|
|
|
|
hints->other_flags = other_flags;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-03-14 11:21:17 +01:00
|
|
|
return FT_Err_Ok;
|
2004-06-04 19:41:59 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** L A T I N G L Y P H G R I D - F I T T I N G *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Snap a given width in scaled coordinates to one of the */
|
|
|
|
/* current standard widths. */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static FT_Pos
|
|
|
|
af_latin_snap_width( AF_Width widths,
|
2015-02-19 10:44:18 +01:00
|
|
|
FT_UInt count,
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Pos width )
|
|
|
|
{
|
2015-02-19 10:44:18 +01:00
|
|
|
FT_UInt n;
|
|
|
|
FT_Pos best = 64 + 32 + 2;
|
|
|
|
FT_Pos reference = width;
|
|
|
|
FT_Pos scaled;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
for ( n = 0; n < count; n++ )
|
|
|
|
{
|
|
|
|
FT_Pos w;
|
|
|
|
FT_Pos dist;
|
|
|
|
|
|
|
|
|
|
|
|
w = widths[n].cur;
|
|
|
|
dist = width - w;
|
|
|
|
if ( dist < 0 )
|
|
|
|
dist = -dist;
|
|
|
|
if ( dist < best )
|
|
|
|
{
|
|
|
|
best = dist;
|
|
|
|
reference = w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scaled = FT_PIX_ROUND( reference );
|
|
|
|
|
|
|
|
if ( width >= reference )
|
|
|
|
{
|
|
|
|
if ( width < scaled + 48 )
|
|
|
|
width = reference;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( width > scaled - 48 )
|
|
|
|
width = reference;
|
|
|
|
}
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Compute the snapped width of a given stem, ignoring very thin ones. */
|
|
|
|
/* There is a lot of voodoo in this function; changing the hard-coded */
|
|
|
|
/* parameters influence the whole hinting process. */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
static FT_Pos
|
|
|
|
af_latin_compute_stem_width( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim,
|
|
|
|
FT_Pos width,
|
2015-02-19 09:46:48 +01:00
|
|
|
FT_UInt base_flags,
|
|
|
|
FT_UInt stem_flags )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2013-08-25 13:07:08 +02:00
|
|
|
AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
|
|
|
|
AF_LatinAxis axis = &metrics->axis[dim];
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Pos dist = width;
|
|
|
|
FT_Int sign = 0;
|
2005-09-26 11:27:09 +02:00
|
|
|
FT_Int vertical = ( dim == AF_DIMENSION_VERT );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
2007-04-02 15:13:54 +02:00
|
|
|
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
|
2011-02-26 18:39:10 +01:00
|
|
|
axis->extra_light )
|
2004-03-27 09:43:17 +01:00
|
|
|
return width;
|
|
|
|
|
|
|
|
if ( dist < 0 )
|
|
|
|
{
|
|
|
|
dist = -width;
|
|
|
|
sign = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
|
|
|
|
( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
|
|
|
|
{
|
|
|
|
/* smooth hinting process: very lightly quantize the stem width */
|
|
|
|
|
|
|
|
/* leave the widths of serifs alone */
|
2011-02-26 18:39:10 +01:00
|
|
|
if ( ( stem_flags & AF_EDGE_SERIF ) &&
|
|
|
|
vertical &&
|
|
|
|
( dist < 3 * 64 ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
goto Done_Width;
|
|
|
|
|
2011-04-04 13:02:08 +02:00
|
|
|
else if ( base_flags & AF_EDGE_ROUND )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
if ( dist < 80 )
|
|
|
|
dist = 64;
|
|
|
|
}
|
|
|
|
else if ( dist < 56 )
|
|
|
|
dist = 56;
|
|
|
|
|
|
|
|
if ( axis->width_count > 0 )
|
|
|
|
{
|
|
|
|
FT_Pos delta;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
/* compare to standard width */
|
2010-09-13 07:32:22 +02:00
|
|
|
delta = dist - axis->widths[0].cur;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2010-09-13 07:32:22 +02:00
|
|
|
if ( delta < 0 )
|
|
|
|
delta = -delta;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2010-09-13 07:32:22 +02:00
|
|
|
if ( delta < 40 )
|
|
|
|
{
|
|
|
|
dist = axis->widths[0].cur;
|
|
|
|
if ( dist < 48 )
|
|
|
|
dist = 48;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2010-09-13 07:32:22 +02:00
|
|
|
goto Done_Width;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( dist < 3 * 64 )
|
|
|
|
{
|
|
|
|
delta = dist & 63;
|
|
|
|
dist &= -64;
|
|
|
|
|
|
|
|
if ( delta < 10 )
|
|
|
|
dist += delta;
|
|
|
|
|
|
|
|
else if ( delta < 32 )
|
|
|
|
dist += 10;
|
|
|
|
|
|
|
|
else if ( delta < 54 )
|
|
|
|
dist += 54;
|
|
|
|
|
|
|
|
else
|
|
|
|
dist += delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dist = ( dist + 32 ) & ~63;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* strong hinting process: snap the stem width to integer pixels */
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2006-11-10 17:49:42 +01:00
|
|
|
FT_Pos org_dist = dist;
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2006-11-14 11:37:10 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
|
|
|
|
|
|
|
|
if ( vertical )
|
|
|
|
{
|
|
|
|
/* in the case of vertical hinting, always round */
|
|
|
|
/* the stem heights to integer pixels */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( dist >= 64 )
|
|
|
|
dist = ( dist + 16 ) & ~63;
|
|
|
|
else
|
|
|
|
dist = 64;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( AF_LATIN_HINTS_DO_MONO( hints ) )
|
|
|
|
{
|
|
|
|
/* monochrome horizontal hinting: snap widths to integer pixels */
|
|
|
|
/* with a different threshold */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( dist < 64 )
|
|
|
|
dist = 64;
|
|
|
|
else
|
|
|
|
dist = ( dist + 32 ) & ~63;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* for horizontal anti-aliased hinting, we adopt a more subtle */
|
|
|
|
/* approach: we strengthen small stems, round stems whose size */
|
|
|
|
/* is between 1 and 2 pixels to an integer, otherwise nothing */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( dist < 48 )
|
|
|
|
dist = ( dist + 64 ) >> 1;
|
|
|
|
|
|
|
|
else if ( dist < 128 )
|
2006-11-10 17:49:42 +01:00
|
|
|
{
|
2006-11-14 11:37:10 +01:00
|
|
|
/* We only round to an integer width if the corresponding */
|
|
|
|
/* distortion is less than 1/4 pixel. Otherwise this */
|
|
|
|
/* makes everything worse since the diagonals, which are */
|
|
|
|
/* not hinted, appear a lot bolder or thinner than the */
|
|
|
|
/* vertical stems. */
|
|
|
|
|
2009-07-31 17:32:08 +02:00
|
|
|
FT_Pos delta;
|
2006-11-10 17:49:42 +01:00
|
|
|
|
2006-11-14 11:37:10 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
dist = ( dist + 22 ) & ~63;
|
2006-11-10 17:49:42 +01:00
|
|
|
delta = dist - org_dist;
|
|
|
|
if ( delta < 0 )
|
|
|
|
delta = -delta;
|
|
|
|
|
2013-03-23 14:25:43 +01:00
|
|
|
if ( delta >= 16 )
|
2006-11-10 17:49:42 +01:00
|
|
|
{
|
|
|
|
dist = org_dist;
|
|
|
|
if ( dist < 48 )
|
2006-11-14 11:37:10 +01:00
|
|
|
dist = ( dist + 64 ) >> 1;
|
2006-11-10 17:49:42 +01:00
|
|
|
}
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
else
|
|
|
|
/* round otherwise to prevent color fringes in LCD mode */
|
|
|
|
dist = ( dist + 32 ) & ~63;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Done_Width:
|
|
|
|
if ( sign )
|
|
|
|
dist = -dist;
|
|
|
|
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Align one stem edge relative to the previous stem edge. */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
|
|
|
af_latin_align_linked_edge( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim,
|
|
|
|
AF_Edge base_edge,
|
|
|
|
AF_Edge stem_edge )
|
|
|
|
{
|
|
|
|
FT_Pos dist = stem_edge->opos - base_edge->opos;
|
|
|
|
|
2015-02-19 09:46:48 +01:00
|
|
|
FT_Pos fitted_width = af_latin_compute_stem_width( hints, dim, dist,
|
|
|
|
base_edge->flags,
|
|
|
|
stem_edge->flags );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
stem_edge->pos = base_edge->pos + fitted_width;
|
2006-11-02 17:37:35 +01:00
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f,"
|
2011-04-18 19:05:28 +02:00
|
|
|
" dist was %.2f, now %.2f\n",
|
2014-04-20 22:11:27 +02:00
|
|
|
stem_edge - hints->axis[dim].edges, stem_edge->opos / 64.0,
|
2011-04-18 19:05:28 +02:00
|
|
|
stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Shift the coordinates of the `serif' edge by the same amount */
|
|
|
|
/* as the corresponding `base' edge has been moved already. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static void
|
|
|
|
af_latin_align_serif_edge( AF_GlyphHints hints,
|
|
|
|
AF_Edge base,
|
|
|
|
AF_Edge serif )
|
|
|
|
{
|
|
|
|
FT_UNUSED( hints );
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
serif->pos = base->pos + ( serif->opos - base->opos );
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/**** ****/
|
2005-03-02 12:24:23 +01:00
|
|
|
/**** E D G E H I N T I N G ****/
|
2004-03-27 09:43:17 +01:00
|
|
|
/**** ****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* The main grid-fitting routine. */
|
|
|
|
|
2015-03-01 19:27:09 +01:00
|
|
|
static void
|
2005-03-02 12:24:23 +01:00
|
|
|
af_latin_hint_edges( AF_GlyphHints hints,
|
|
|
|
AF_Dimension dim )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
AF_AxisHints axis = &hints->axis[dim];
|
|
|
|
AF_Edge edges = axis->edges;
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Edge edge_limit = edges + axis->num_edges;
|
2009-07-31 17:32:07 +02:00
|
|
|
FT_PtrDist n_edges;
|
2004-03-27 09:43:17 +01:00
|
|
|
AF_Edge edge;
|
2011-02-26 18:39:10 +01:00
|
|
|
AF_Edge anchor = NULL;
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Int has_serifs = 0;
|
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
FT_UInt num_actions = 0;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
|
2013-08-26 20:20:03 +02:00
|
|
|
dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
|
[autofit] Introduce `styles'.
This is the new top-level structure for handling glyph input data;
scripts are now defined separately.
* src/autofit/aftypes.h (SCRIPT): Updated.
(AF_ScriptClassRec): Move `blue_stringset' and `writing_system'
members to ...
(AF_Style_ClassRec): ... this new structure.
(AF_Style): New enumeration.
(AF_StyleMetricsRec): Replace `script' enumeration with
`style_class' pointer.
(AF_DEFINE_SCRIPT_CLASS, AF_DECLARE_SCRIPT_CLASS): Updated.
(AF_DEFINE_STYLE_CLASS, AF_DECLARE_STYLE_CLASS): New macros.
* src/autofit/afstyles.h: New file, using data from `afscript.h'.
* src/autofit/afscript.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init_widths,
af_cjk_metrics_init_blues, af_cjk_hint_edges): Updated.
* src/autofit/afglobal.c (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(af_script_names) [FT_DEBUG_LEVEL_TRACE]: Replace with...
(af_style_names): ... this array.
(af_face_globals_compute_script_coverage): Renamed to...
(af_face_globals_compute_style_coverage): ... this.
Updated.
(af_face_globals_new, af_face_globals_free,
af_face_globals_get_metrics): Updated.
* src/autofit/afglobal.h (SCRIPT): Updated.
(STYLE): Redefine macro to load `afstyles.h'.
(AF_SCRIPT_FALLBACK): Update definition. This will get more
refinements with later on.
(AF_SCRIPT_UNASSIGNED): Replace with...
(AF_STYLE_UNASSIGNED): ... this macro.
(AF_FaceGlobalsRec): Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues, af_latin_metrics_scale_dim,
af_latin_hint_edges): Updated.
* src/autofit/aflatin2.c (af_latin2_metrics_init_widths): Updated.
(af_ltn2_uniranges): Removed.
* src/autofit/afloader.c (af_loader_load_g, af_loader_load_glyph):
Updated.
* src/autofit/afpic.c (autofit_module_class_pic_init): Updated.
* src/autofit/afpic.h (AF_STYLE_CLASSES_GET): New macro.
(AFModulePIC): Add `af_style_classes' and `af_style_classes_rec'
members.
* src/autofit/afranges.h: Updated.
* src/autofit/rules.mk (AUTOF_DRV_H): Add `afstyles.h'.
2013-12-20 17:26:26 +01:00
|
|
|
af_style_names[hints->metrics->style_class->style] ));
|
2011-04-28 09:09:45 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
/* we begin by aligning all stems relative to the blue zone */
|
|
|
|
/* if needed -- that's only for horizontal edges */
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
for ( edge = edges; edge < edge_limit; edge++ )
|
|
|
|
{
|
|
|
|
AF_Width blue;
|
2011-05-02 06:04:15 +02:00
|
|
|
AF_Edge edge1, edge2; /* these edges form the stem to check */
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
if ( edge->flags & AF_EDGE_DONE )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
edge1 = NULL;
|
|
|
|
edge2 = edge->link;
|
|
|
|
|
2014-05-01 07:16:05 +02:00
|
|
|
/*
|
|
|
|
* If a stem contains both a neutral and a non-neutral blue zone,
|
|
|
|
* skip the neutral one. Otherwise, outlines with different
|
|
|
|
* directions might be incorrectly aligned at the same vertical
|
|
|
|
* position.
|
|
|
|
*
|
|
|
|
* If we have two neutral blue zones, skip one of them.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
if ( edge->blue_edge && edge2 && edge2->blue_edge )
|
|
|
|
{
|
|
|
|
FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
|
|
|
|
FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
|
|
|
|
|
|
|
|
|
2015-04-03 05:15:36 +02:00
|
|
|
if ( neutral2 )
|
2014-05-01 07:16:05 +02:00
|
|
|
{
|
|
|
|
edge2->blue_edge = NULL;
|
|
|
|
edge2->flags &= ~AF_EDGE_NEUTRAL;
|
|
|
|
}
|
|
|
|
else if ( neutral )
|
|
|
|
{
|
|
|
|
edge->blue_edge = NULL;
|
|
|
|
edge->flags &= ~AF_EDGE_NEUTRAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
blue = edge->blue_edge;
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( blue )
|
|
|
|
edge1 = edge;
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2014-05-01 07:16:05 +02:00
|
|
|
/* flip edges if the other edge is aligned to a blue zone */
|
2004-03-27 09:43:17 +01:00
|
|
|
else if ( edge2 && edge2->blue_edge )
|
|
|
|
{
|
|
|
|
blue = edge2->blue_edge;
|
|
|
|
edge1 = edge2;
|
|
|
|
edge2 = edge;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !edge1 )
|
|
|
|
continue;
|
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2013-03-23 14:25:43 +01:00
|
|
|
if ( !anchor )
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f,"
|
|
|
|
" was %.2f (anchor=edge %d)\n",
|
|
|
|
edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
|
|
|
|
edge1->pos / 64.0, edge - edges ));
|
|
|
|
else
|
|
|
|
FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f,"
|
|
|
|
" was %.2f\n",
|
|
|
|
edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
|
|
|
|
edge1->pos / 64.0 ));
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
num_actions++;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
edge1->pos = blue->fit;
|
|
|
|
edge1->flags |= AF_EDGE_DONE;
|
|
|
|
|
|
|
|
if ( edge2 && !edge2->blue_edge )
|
|
|
|
{
|
|
|
|
af_latin_align_linked_edge( hints, dim, edge1, edge2 );
|
|
|
|
edge2->flags |= AF_EDGE_DONE;
|
2012-11-10 12:42:18 +01:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
num_actions++;
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( !anchor )
|
|
|
|
anchor = edge;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-02 06:04:15 +02:00
|
|
|
/* now we align all other stem edges, trying to maintain the */
|
|
|
|
/* relative order of stems in the glyph */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( edge = edges; edge < edge_limit; edge++ )
|
|
|
|
{
|
|
|
|
AF_Edge edge2;
|
|
|
|
|
|
|
|
|
|
|
|
if ( edge->flags & AF_EDGE_DONE )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip all non-stem edges */
|
|
|
|
edge2 = edge->link;
|
|
|
|
if ( !edge2 )
|
|
|
|
{
|
|
|
|
has_serifs++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now align the stem */
|
|
|
|
|
|
|
|
/* this should not happen, but it's better to be safe */
|
2006-11-23 15:49:48 +01:00
|
|
|
if ( edge2->blue_edge )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
2014-05-01 07:16:05 +02:00
|
|
|
FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges ));
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_align_linked_edge( hints, dim, edge2, edge );
|
|
|
|
edge->flags |= AF_EDGE_DONE;
|
2012-11-10 12:42:18 +01:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
num_actions++;
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !anchor )
|
|
|
|
{
|
2011-05-02 06:04:15 +02:00
|
|
|
/* if we reach this if clause, no stem has been aligned yet */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Pos org_len, org_center, cur_len;
|
|
|
|
FT_Pos cur_pos1, error1, error2, u_off, d_off;
|
|
|
|
|
|
|
|
|
|
|
|
org_len = edge2->opos - edge->opos;
|
2015-02-19 09:46:48 +01:00
|
|
|
cur_len = af_latin_compute_stem_width( hints, dim, org_len,
|
|
|
|
edge->flags,
|
|
|
|
edge2->flags );
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2011-05-02 06:04:15 +02:00
|
|
|
/* some voodoo to specially round edges for small stem widths; */
|
|
|
|
/* the idea is to align the center of a stem, then shifting */
|
|
|
|
/* the stem edges to suitable positions */
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( cur_len <= 64 )
|
2011-02-26 18:39:10 +01:00
|
|
|
{
|
2011-05-02 06:04:15 +02:00
|
|
|
/* width <= 1px */
|
2011-02-26 18:39:10 +01:00
|
|
|
u_off = 32;
|
|
|
|
d_off = 32;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
else
|
|
|
|
{
|
2011-05-02 06:04:15 +02:00
|
|
|
/* 1px < width < 1.5px */
|
2004-03-27 09:43:17 +01:00
|
|
|
u_off = 38;
|
|
|
|
d_off = 26;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( cur_len < 96 )
|
|
|
|
{
|
|
|
|
org_center = edge->opos + ( org_len >> 1 );
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_center );
|
|
|
|
|
|
|
|
error1 = org_center - ( cur_pos1 - u_off );
|
|
|
|
if ( error1 < 0 )
|
|
|
|
error1 = -error1;
|
|
|
|
|
|
|
|
error2 = org_center - ( cur_pos1 + d_off );
|
|
|
|
if ( error2 < 0 )
|
|
|
|
error2 = -error2;
|
|
|
|
|
|
|
|
if ( error1 < error2 )
|
|
|
|
cur_pos1 -= u_off;
|
|
|
|
else
|
|
|
|
cur_pos1 += d_off;
|
|
|
|
|
|
|
|
edge->pos = cur_pos1 - cur_len / 2;
|
2006-11-23 15:49:48 +01:00
|
|
|
edge2->pos = edge->pos + cur_len;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
edge->pos = FT_PIX_ROUND( edge->opos );
|
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
anchor = edge;
|
|
|
|
edge->flags |= AF_EDGE_DONE;
|
|
|
|
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
|
2012-07-09 08:19:25 +02:00
|
|
|
" snapped to %.2f and %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->opos / 64.0,
|
|
|
|
edge2 - edges, edge2->opos / 64.0,
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
af_latin_align_linked_edge( hints, dim, edge, edge2 );
|
2012-11-10 12:42:18 +01:00
|
|
|
|
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
num_actions += 2;
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FT_Pos org_pos, org_len, org_center, cur_len;
|
|
|
|
FT_Pos cur_pos1, cur_pos2, delta1, delta2;
|
|
|
|
|
|
|
|
|
|
|
|
org_pos = anchor->pos + ( edge->opos - anchor->opos );
|
|
|
|
org_len = edge2->opos - edge->opos;
|
|
|
|
org_center = org_pos + ( org_len >> 1 );
|
|
|
|
|
2015-02-19 09:46:48 +01:00
|
|
|
cur_len = af_latin_compute_stem_width( hints, dim, org_len,
|
|
|
|
edge->flags,
|
|
|
|
edge2->flags );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-11-03 00:28:09 +01:00
|
|
|
if ( edge2->flags & AF_EDGE_DONE )
|
2011-05-27 10:22:42 +02:00
|
|
|
{
|
|
|
|
FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n",
|
|
|
|
edge - edges, edge->pos / 64.0,
|
|
|
|
( edge2->pos - cur_len ) / 64.0 ));
|
|
|
|
|
2006-11-03 10:40:12 +01:00
|
|
|
edge->pos = edge2->pos - cur_len;
|
2011-05-27 10:22:42 +02:00
|
|
|
}
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2006-11-03 00:28:09 +01:00
|
|
|
else if ( cur_len < 96 )
|
2004-03-27 09:43:17 +01:00
|
|
|
{
|
|
|
|
FT_Pos u_off, d_off;
|
|
|
|
|
|
|
|
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_center );
|
|
|
|
|
2013-03-23 14:25:43 +01:00
|
|
|
if ( cur_len <= 64 )
|
2011-02-26 18:39:10 +01:00
|
|
|
{
|
|
|
|
u_off = 32;
|
|
|
|
d_off = 32;
|
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
u_off = 38;
|
|
|
|
d_off = 26;
|
|
|
|
}
|
|
|
|
|
|
|
|
delta1 = org_center - ( cur_pos1 - u_off );
|
|
|
|
if ( delta1 < 0 )
|
|
|
|
delta1 = -delta1;
|
|
|
|
|
|
|
|
delta2 = org_center - ( cur_pos1 + d_off );
|
|
|
|
if ( delta2 < 0 )
|
|
|
|
delta2 = -delta2;
|
|
|
|
|
|
|
|
if ( delta1 < delta2 )
|
|
|
|
cur_pos1 -= u_off;
|
|
|
|
else
|
|
|
|
cur_pos1 += d_off;
|
|
|
|
|
|
|
|
edge->pos = cur_pos1 - cur_len / 2;
|
|
|
|
edge2->pos = cur_pos1 + cur_len / 2;
|
2006-11-03 10:40:12 +01:00
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
|
|
|
|
" snapped to %.2f and %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->opos / 64.0,
|
|
|
|
edge2 - edges, edge2->opos / 64.0,
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
2012-11-10 12:42:18 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
org_pos = anchor->pos + ( edge->opos - anchor->opos );
|
|
|
|
org_len = edge2->opos - edge->opos;
|
|
|
|
org_center = org_pos + ( org_len >> 1 );
|
|
|
|
|
2015-02-19 09:46:48 +01:00
|
|
|
cur_len = af_latin_compute_stem_width( hints, dim, org_len,
|
|
|
|
edge->flags,
|
|
|
|
edge2->flags );
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
cur_pos1 = FT_PIX_ROUND( org_pos );
|
|
|
|
delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( delta1 < 0 )
|
|
|
|
delta1 = -delta1;
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
|
|
|
|
delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( delta2 < 0 )
|
|
|
|
delta2 = -delta2;
|
|
|
|
|
|
|
|
edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
|
|
|
|
edge2->pos = edge->pos + cur_len;
|
2006-11-02 17:37:35 +01:00
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
|
|
|
|
" snapped to %.2f and %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->opos / 64.0,
|
|
|
|
edge2 - edges, edge2->opos / 64.0,
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
num_actions++;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->flags |= AF_EDGE_DONE;
|
|
|
|
edge2->flags |= AF_EDGE_DONE;
|
|
|
|
|
|
|
|
if ( edge > edges && edge->pos < edge[-1].pos )
|
2006-11-02 17:37:35 +01:00
|
|
|
{
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
|
2012-07-09 08:19:25 +02:00
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
num_actions++;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->pos = edge[-1].pos;
|
2006-11-02 17:37:35 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure that lowercase m's maintain their symmetry */
|
|
|
|
|
|
|
|
/* In general, lowercase m's have six vertical edges if they are sans */
|
2005-03-02 12:24:23 +01:00
|
|
|
/* serif, or twelve if they are with serifs. This implementation is */
|
2004-03-27 09:43:17 +01:00
|
|
|
/* based on that assumption, and seems to work very well with most */
|
|
|
|
/* faces. However, if for a certain face this assumption is not */
|
|
|
|
/* true, the m is just rendered like before. In addition, any stem */
|
|
|
|
/* correction will only be applied to symmetrical glyphs (even if the */
|
|
|
|
/* glyph is not an m), so the potential for unwanted distortion is */
|
|
|
|
/* relatively low. */
|
|
|
|
|
|
|
|
/* We don't handle horizontal edges since we can't easily assure that */
|
|
|
|
/* the third (lowest) stem aligns with the base line; it might end up */
|
|
|
|
/* one pixel higher or lower. */
|
|
|
|
|
|
|
|
n_edges = edge_limit - edges;
|
|
|
|
if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
|
|
|
|
{
|
|
|
|
AF_Edge edge1, edge2, edge3;
|
|
|
|
FT_Pos dist1, dist2, span, delta;
|
|
|
|
|
|
|
|
|
|
|
|
if ( n_edges == 6 )
|
|
|
|
{
|
|
|
|
edge1 = edges;
|
|
|
|
edge2 = edges + 2;
|
|
|
|
edge3 = edges + 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
edge1 = edges + 1;
|
|
|
|
edge2 = edges + 5;
|
|
|
|
edge3 = edges + 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
dist1 = edge2->opos - edge1->opos;
|
|
|
|
dist2 = edge3->opos - edge2->opos;
|
|
|
|
|
|
|
|
span = dist1 - dist2;
|
|
|
|
if ( span < 0 )
|
|
|
|
span = -span;
|
|
|
|
|
|
|
|
if ( span < 8 )
|
|
|
|
{
|
|
|
|
delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
|
|
|
|
edge3->pos -= delta;
|
|
|
|
if ( edge3->link )
|
|
|
|
edge3->link->pos -= delta;
|
|
|
|
|
|
|
|
/* move the serifs along with the stem */
|
|
|
|
if ( n_edges == 12 )
|
|
|
|
{
|
|
|
|
( edges + 8 )->pos -= delta;
|
|
|
|
( edges + 11 )->pos -= delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
edge3->flags |= AF_EDGE_DONE;
|
|
|
|
if ( edge3->link )
|
|
|
|
edge3->link->flags |= AF_EDGE_DONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( has_serifs || !anchor )
|
|
|
|
{
|
2005-03-02 12:24:23 +01:00
|
|
|
/*
|
|
|
|
* now hint the remaining edges (serifs and single) in order
|
|
|
|
* to complete our processing
|
|
|
|
*/
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( edge = edges; edge < edge_limit; edge++ )
|
|
|
|
{
|
2006-11-23 15:49:48 +01:00
|
|
|
FT_Pos delta;
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( edge->flags & AF_EDGE_DONE )
|
|
|
|
continue;
|
|
|
|
|
2006-11-23 15:49:48 +01:00
|
|
|
delta = 1000;
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
if ( edge->serif )
|
2006-11-23 15:49:48 +01:00
|
|
|
{
|
|
|
|
delta = edge->serif->opos - edge->opos;
|
|
|
|
if ( delta < 0 )
|
|
|
|
delta = -delta;
|
|
|
|
}
|
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
if ( delta < 64 + 16 )
|
2006-11-23 15:49:48 +01:00
|
|
|
{
|
2004-03-27 09:43:17 +01:00
|
|
|
af_latin_align_serif_edge( hints, edge->serif, edge );
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
|
2012-07-09 08:19:25 +02:00
|
|
|
" aligned to %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->opos / 64.0,
|
|
|
|
edge->serif - edges, edge->serif->opos / 64.0,
|
|
|
|
edge->pos / 64.0 ));
|
2006-11-23 15:49:48 +01:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
else if ( !anchor )
|
|
|
|
{
|
2011-05-27 10:22:42 +02:00
|
|
|
edge->pos = FT_PIX_ROUND( edge->opos );
|
|
|
|
anchor = edge;
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)"
|
2012-07-09 08:19:25 +02:00
|
|
|
" snapped to %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
else
|
2006-11-23 15:49:48 +01:00
|
|
|
{
|
2006-12-01 09:20:47 +01:00
|
|
|
AF_Edge before, after;
|
2006-11-23 15:49:48 +01:00
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
|
|
|
|
for ( before = edge - 1; before >= edges; before-- )
|
2006-11-23 15:49:48 +01:00
|
|
|
if ( before->flags & AF_EDGE_DONE )
|
2006-12-01 09:20:47 +01:00
|
|
|
break;
|
2006-11-23 15:49:48 +01:00
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
for ( after = edge + 1; after < edge_limit; after++ )
|
2006-11-23 15:49:48 +01:00
|
|
|
if ( after->flags & AF_EDGE_DONE )
|
2006-12-01 09:20:47 +01:00
|
|
|
break;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2006-12-01 09:20:47 +01:00
|
|
|
if ( before >= edges && before < edge &&
|
|
|
|
after < edge_limit && after > edge )
|
2007-06-11 07:37:35 +02:00
|
|
|
{
|
2008-12-21 10:46:31 +01:00
|
|
|
if ( after->opos == before->opos )
|
|
|
|
edge->pos = before->pos;
|
|
|
|
else
|
|
|
|
edge->pos = before->pos +
|
2006-12-01 09:20:47 +01:00
|
|
|
FT_MulDiv( edge->opos - before->opos,
|
|
|
|
after->pos - before->pos,
|
|
|
|
after->opos - before->opos );
|
2011-02-26 18:39:10 +01:00
|
|
|
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f"
|
2011-04-18 19:05:28 +02:00
|
|
|
" from %d (opos=%.2f)\n",
|
|
|
|
edge - edges, edge->opos / 64.0,
|
|
|
|
edge->pos / 64.0,
|
|
|
|
before - edges, before->opos / 64.0 ));
|
2007-06-11 07:37:35 +02:00
|
|
|
}
|
2006-11-23 15:49:48 +01:00
|
|
|
else
|
2007-06-11 07:37:35 +02:00
|
|
|
{
|
2007-06-11 23:15:09 +02:00
|
|
|
edge->pos = anchor->pos +
|
|
|
|
( ( edge->opos - anchor->opos + 16 ) & ~31 );
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)"
|
2012-07-09 08:19:25 +02:00
|
|
|
" snapped to %.2f\n",
|
2011-04-18 19:05:28 +02:00
|
|
|
edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
|
2007-06-11 07:37:35 +02:00
|
|
|
}
|
2006-11-23 15:49:48 +01:00
|
|
|
}
|
2006-12-01 09:20:47 +01:00
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
num_actions++;
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->flags |= AF_EDGE_DONE;
|
|
|
|
|
|
|
|
if ( edge > edges && edge->pos < edge[-1].pos )
|
2012-07-09 08:19:25 +02:00
|
|
|
{
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
|
|
|
|
edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
|
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
num_actions++;
|
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->pos = edge[-1].pos;
|
2012-07-09 08:19:25 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
|
|
|
if ( edge + 1 < edge_limit &&
|
|
|
|
edge[1].flags & AF_EDGE_DONE &&
|
|
|
|
edge->pos > edge[1].pos )
|
2012-07-09 08:19:25 +02:00
|
|
|
{
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
2012-07-09 08:19:25 +02:00
|
|
|
FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
|
|
|
|
edge - edges, edge->pos / 64.0, edge[1].pos / 64.0 ));
|
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
num_actions++;
|
|
|
|
#endif
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
edge->pos = edge[1].pos;
|
2012-07-09 08:19:25 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2011-04-28 09:09:45 +02:00
|
|
|
|
2012-11-10 12:42:18 +01:00
|
|
|
#ifdef FT_DEBUG_LEVEL_TRACE
|
|
|
|
if ( !num_actions )
|
|
|
|
FT_TRACE5(( " (none)\n" ));
|
2011-04-28 09:09:45 +02:00
|
|
|
FT_TRACE5(( "\n" ));
|
2012-11-10 12:42:18 +01:00
|
|
|
#endif
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-26 18:39:10 +01:00
|
|
|
/* Apply the complete hinting algorithm to a latin glyph. */
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
static FT_Error
|
2015-09-03 06:47:30 +02:00
|
|
|
af_latin_hints_apply( FT_UInt glyph_index,
|
|
|
|
AF_GlyphHints hints,
|
2004-03-27 09:43:17 +01:00
|
|
|
FT_Outline* outline,
|
|
|
|
AF_LatinMetrics metrics )
|
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
FT_Error error;
|
|
|
|
int dim;
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2014-04-05 16:27:19 +02:00
|
|
|
AF_LatinAxis axis;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
2010-05-22 07:43:22 +02:00
|
|
|
error = af_glyph_hints_reload( hints, outline );
|
2004-06-04 19:41:59 +02:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* analyze glyph outline */
|
2011-03-02 03:52:36 +01:00
|
|
|
#ifdef AF_CONFIG_OPTION_USE_WARPER
|
2015-04-16 20:11:49 +02:00
|
|
|
if ( ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT &&
|
|
|
|
AF_HINTS_DO_WARP( hints ) ) ||
|
|
|
|
AF_HINTS_DO_HORIZONTAL( hints ) )
|
2007-01-23 16:51:50 +01:00
|
|
|
#else
|
2005-03-02 12:24:23 +01:00
|
|
|
if ( AF_HINTS_DO_HORIZONTAL( hints ) )
|
2007-01-23 16:51:50 +01:00
|
|
|
#endif
|
2005-03-01 16:48:29 +01:00
|
|
|
{
|
2014-04-05 16:27:19 +02:00
|
|
|
axis = &metrics->axis[AF_DIMENSION_HORZ];
|
|
|
|
error = af_latin_hints_detect_features( hints,
|
|
|
|
axis->width_count,
|
|
|
|
axis->widths,
|
|
|
|
AF_DIMENSION_HORZ );
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
|
|
|
}
|
2004-06-04 19:41:59 +02:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
if ( AF_HINTS_DO_VERTICAL( hints ) )
|
2004-06-04 19:41:59 +02:00
|
|
|
{
|
2014-04-05 16:27:19 +02:00
|
|
|
axis = &metrics->axis[AF_DIMENSION_VERT];
|
|
|
|
error = af_latin_hints_detect_features( hints,
|
|
|
|
axis->width_count,
|
|
|
|
axis->widths,
|
|
|
|
AF_DIMENSION_VERT );
|
2005-03-01 16:48:29 +01:00
|
|
|
if ( error )
|
|
|
|
goto Exit;
|
|
|
|
|
2015-09-04 10:28:53 +02:00
|
|
|
/* apply blue zones to base characters only */
|
2015-09-30 17:52:42 +02:00
|
|
|
if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
|
2015-09-04 10:28:53 +02:00
|
|
|
af_latin_hints_compute_blue_edges( hints, metrics );
|
2004-06-04 19:41:59 +02:00
|
|
|
}
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* grid-fit the outline */
|
2004-03-27 09:43:17 +01:00
|
|
|
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
|
|
|
|
{
|
2011-03-02 03:52:36 +01:00
|
|
|
#ifdef AF_CONFIG_OPTION_USE_WARPER
|
2011-02-26 18:39:10 +01:00
|
|
|
if ( dim == AF_DIMENSION_HORZ &&
|
2015-04-16 20:11:49 +02:00
|
|
|
metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT &&
|
|
|
|
AF_HINTS_DO_WARP( hints ) )
|
2007-01-23 16:51:50 +01:00
|
|
|
{
|
|
|
|
AF_WarperRec warper;
|
|
|
|
FT_Fixed scale;
|
|
|
|
FT_Pos delta;
|
2006-01-22 07:58:16 +01:00
|
|
|
|
2006-01-21 15:31:45 +01:00
|
|
|
|
2011-03-19 02:28:21 +01:00
|
|
|
af_warper_compute( &warper, hints, (AF_Dimension)dim,
|
|
|
|
&scale, &delta );
|
|
|
|
af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
|
|
|
|
scale, delta );
|
2007-01-23 16:51:50 +01:00
|
|
|
continue;
|
|
|
|
}
|
2015-04-16 20:11:49 +02:00
|
|
|
#endif /* AF_CONFIG_OPTION_USE_WARPER */
|
2007-01-23 16:51:50 +01:00
|
|
|
|
|
|
|
if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
|
|
|
|
( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
|
|
|
|
{
|
2005-03-03 18:09:08 +01:00
|
|
|
af_latin_hint_edges( hints, (AF_Dimension)dim );
|
|
|
|
af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
|
|
|
|
af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
|
|
|
|
af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
}
|
2013-08-25 13:07:08 +02:00
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
af_glyph_hints_save( hints, outline );
|
|
|
|
|
2004-06-04 19:41:59 +02:00
|
|
|
Exit:
|
|
|
|
return error;
|
2004-03-27 09:43:17 +01:00
|
|
|
}
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** L A T I N S C R I P T C L A S S *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
|
2004-03-27 09:43:17 +01:00
|
|
|
|
2013-07-31 22:49:29 +02:00
|
|
|
AF_DEFINE_WRITING_SYSTEM_CLASS(
|
|
|
|
af_latin_writing_system_class,
|
|
|
|
|
|
|
|
AF_WRITING_SYSTEM_LATIN,
|
|
|
|
|
|
|
|
sizeof ( AF_LatinMetricsRec ),
|
|
|
|
|
2013-12-17 13:29:53 +01:00
|
|
|
(AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,
|
|
|
|
(AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,
|
|
|
|
(AF_WritingSystem_DoneMetricsFunc) NULL,
|
2015-11-02 09:32:26 +01:00
|
|
|
(AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths,
|
2013-07-31 22:49:29 +02:00
|
|
|
|
2013-12-17 13:29:53 +01:00
|
|
|
(AF_WritingSystem_InitHintsFunc) af_latin_hints_init,
|
|
|
|
(AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply
|
2013-07-31 22:49:29 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2005-03-02 12:24:23 +01:00
|
|
|
/* END */
|