Created
September 16, 2021 06:48
-
-
Save uivil/a11915f183eabf8f1ca23d2fcbdc54c5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/config.mk a/config.mk | |
--- b/config.mk 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/config.mk 2021-09-16 09:19:40.891396586 +0300 | |
@@ -0,0 +1,62 @@ | |
+# | |
+# FreeType 2 configuration rules for UNIX platforms | |
+# | |
+ | |
+ | |
+# Copyright (C) 1996-2021 by | |
+# David Turner, Robert Wilhelm, and Werner Lemberg. | |
+# | |
+# This file is part of the FreeType project, and may only be used, modified, | |
+# and distributed under the terms of the FreeType project license, | |
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you | |
+# indicate that you have read the license and understand and accept it | |
+# fully. | |
+ | |
+# We need these declarations here since unix-def.mk is a generated file. | |
+PLATFORM_DIR := $(TOP_DIR)/builds/unix | |
+PLATFORM := unix | |
+ | |
+have_mk := $(wildcard $(OBJ_DIR)/unix-def.mk) | |
+ifneq ($(have_mk),) | |
+ # We are building FreeType 2 not in the src tree. | |
+ include $(OBJ_DIR)/unix-def.mk | |
+ include $(OBJ_DIR)/unix-cc.mk | |
+else | |
+ include $(PLATFORM_DIR)/unix-def.mk | |
+ include $(PLATFORM_DIR)/unix-cc.mk | |
+endif | |
+ | |
+ifdef BUILD_PROJECT | |
+ | |
+ .PHONY: clean_project distclean_project | |
+ | |
+ # Now include the main sub-makefile. It contains all the rules used to | |
+ # build the library with the previous variables defined. | |
+ # | |
+ include $(TOP_DIR)/builds/$(PROJECT).mk | |
+ | |
+ | |
+ # The cleanup targets. | |
+ # | |
+ clean_project: clean_project_unix | |
+ distclean_project: distclean_project_unix | |
+ | |
+ | |
+ # This final rule is used to link all object files into a single library. | |
+ # It is part of the system-specific sub-Makefile because not all | |
+ # librarians accept a simple syntax like | |
+ # | |
+ # librarian library_file {list of object files} | |
+ # | |
+ $(PROJECT_LIBRARY): $(OBJECTS_LIST) | |
+ ifdef CLEAN_LIBRARY | |
+ -$(CLEAN_LIBRARY) $(NO_OUTPUT) | |
+ endif | |
+ $(LINK_LIBRARY) | |
+ | |
+ include $(TOP_DIR)/builds/unix/install.mk | |
+ | |
+endif | |
+ | |
+ | |
+# EOF | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/configure a/configure | |
--- b/configure 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/configure 2021-09-16 09:15:05.050379727 +0300 | |
@@ -13,6 +13,8 @@ | |
# Call the `configure' script located in `builds/unix'. | |
# | |
+export LDFLAGS="$LDFLAGS -lm" | |
+ | |
rm -f config.mk builds/unix/unix-def.mk builds/unix/unix-cc.mk | |
# respect GNUMAKE environment variable for backward compatibility | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/devel/ftoption.h a/devel/ftoption.h | |
--- b/devel/ftoption.h 2021-07-15 13:09:04.000000000 +0300 | |
+++ a/devel/ftoption.h 2021-09-16 09:15:05.050379727 +0300 | |
@@ -629,6 +629,16 @@ | |
*/ | |
#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
+ /*************************************************************************/ | |
+ /* */ | |
+ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */ | |
+ /* all additional infinality patches, which are configured via env */ | |
+ /* variables. */ | |
+ /* */ | |
+ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */ | |
+ /* defined. */ | |
+ /* */ | |
+#define FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
/************************************************************************** | |
* | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/include/freetype/config/ftoption.h a/include/freetype/config/ftoption.h | |
--- b/include/freetype/config/ftoption.h 2021-07-15 13:09:04.000000000 +0300 | |
+++ a/include/freetype/config/ftoption.h 2021-09-16 09:15:05.051379735 +0300 | |
@@ -112,18 +112,21 @@ | |
#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES | |
- /************************************************************************** | |
- * | |
- * Uncomment the line below if you want to activate LCD rendering | |
- * technology similar to ClearType in this build of the library. This | |
- * technology triples the resolution in the direction color subpixels. To | |
- * mitigate color fringes inherent to this technology, you also need to | |
- * explicitly set up LCD filtering. | |
- * | |
- * When this macro is not defined, FreeType offers alternative LCD | |
- * rendering technology that produces excellent output. | |
- */ | |
-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
+ /*************************************************************************/ | |
+ /* */ | |
+ /* Uncomment the line below if you want to activate LCD rendering */ | |
+ /* technology similar to ClearType in this build of the library. This */ | |
+ /* technology triples the resolution in the direction color subpixels. */ | |
+ /* To mitigate color fringes inherent to this technology, you also need */ | |
+ /* to explicitly set up LCD filtering. */ | |
+ /* */ | |
+ /* Note that this feature is covered by several Microsoft patents */ | |
+ /* and should not be activated in any default build of the library. */ | |
+ /* When this macro is not defined, FreeType offers alternative LCD */ | |
+ /* rendering technology that produces excellent output without LCD */ | |
+ /* filtering. */ | |
+ /* */ | |
+#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
/************************************************************************** | |
@@ -631,6 +634,17 @@ | |
*/ | |
#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
+ /*************************************************************************/ | |
+ /* */ | |
+ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */ | |
+ /* all additional infinality patches, which are configured via env */ | |
+ /* variables. */ | |
+ /* */ | |
+ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */ | |
+ /* defined. */ | |
+ /* */ | |
+#define FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ | |
/************************************************************************** | |
* | |
@@ -688,8 +702,8 @@ | |
* https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx | |
*/ | |
/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ | |
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 | |
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */ | |
+/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ | |
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) | |
/************************************************************************** | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/include/freetype/internal/ftobjs.h a/include/freetype/internal/ftobjs.h | |
--- b/include/freetype/internal/ftobjs.h 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/include/freetype/internal/ftobjs.h 2021-09-16 09:15:05.051379735 +0300 | |
@@ -278,12 +278,14 @@ | |
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, | |
+ FT_Render_Mode render_mode, | |
FT_Byte* weights ); | |
/* This is the default LCD filter, an in-place, 5-tap FIR filter. */ | |
FT_BASE( void ) | |
ft_lcd_filter_fir( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
FT_LcdFiveTapFilter weights ); | |
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
@@ -908,6 +910,7 @@ | |
FT_DebugHook_Func debug_hooks[4]; | |
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ FT_Int lcd_extra; /* number of extra pixels */ | |
FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ | |
FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ | |
#else | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/aflatin.c a/src/autofit/aflatin.c | |
--- b/src/autofit/aflatin.c 2021-07-12 15:07:00.000000000 +0300 | |
+++ a/src/autofit/aflatin.c 2021-09-16 09:15:05.051379735 +0300 | |
@@ -22,7 +22,10 @@ | |
#include "afglobal.h" | |
#include "aflatin.h" | |
#include "aferrors.h" | |
- | |
+#include "strings.h" | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "../base/ftinf.h" | |
+#endif | |
/************************************************************************** | |
* | |
@@ -33,6 +36,10 @@ | |
#undef FT_COMPONENT | |
#define FT_COMPONENT aflatin | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+FT_Pos infinality_cur_width = 0; | |
+#endif | |
+ | |
/* needed for computation of round vs. flat segments */ | |
#define FLAT_THRESHOLD( x ) ( x / 14 ) | |
@@ -1174,7 +1181,10 @@ | |
FT_Pos delta; | |
AF_LatinAxis axis; | |
FT_UInt nn; | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Bool adjust_heights = FALSE; | |
+ if(ftinf) adjust_heights=ftinf->autohint_increase_glyph_heights; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
if ( dim == AF_DIMENSION_HORZ ) | |
{ | |
@@ -1202,7 +1212,7 @@ | |
{ | |
AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; | |
AF_LatinBlue blue = NULL; | |
- | |
+ int threshold = 40; | |
for ( nn = 0; nn < Axis->blue_count; nn++ ) | |
{ | |
@@ -1212,7 +1222,12 @@ | |
break; | |
} | |
} | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( adjust_heights && | |
+ metrics->root.scaler.face->size->metrics.x_ppem < 15 && | |
+ metrics->root.scaler.face->size->metrics.x_ppem > 5 ) | |
+ threshold = 52; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
if ( blue ) | |
{ | |
FT_Pos scaled; | |
@@ -1369,7 +1384,13 @@ | |
/* a blue zone is only active if it is less than 3/4 pixels tall */ | |
dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); | |
+ | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* Do at low ppems ( ~< 200 ), in order to prevent fringes */ | |
+ if ( dist <= 256 && dist >= -256 ) | |
+#else | |
if ( dist <= 48 && dist >= -48 ) | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
{ | |
#if 0 | |
FT_Pos delta1; | |
@@ -1420,7 +1441,12 @@ | |
delta2 = -delta2; | |
blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* Round to prevent fringes */ | |
+ blue->shoot.fit = FT_PIX_ROUND( blue->ref.fit - delta2 ); | |
+#else | |
blue->shoot.fit = blue->ref.fit - delta2; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
#endif | |
@@ -2583,7 +2609,10 @@ | |
dist = edge->fpos - blue->shoot.org; | |
if ( dist < 0 ) | |
dist = -dist; | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* round down to pixels */ | |
+ /*dist = FT_MulFix( dist, scale ) & ~63;*/ | |
+#endif | |
dist = FT_MulFix( dist, scale ); | |
if ( dist < best_dist ) | |
{ | |
@@ -2748,8 +2777,17 @@ | |
FT_Pos dist = width; | |
FT_Int sign = 0; | |
FT_Int vertical = ( dim == AF_DIMENSION_VERT ); | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Int infinality_dist = 0; | |
+ FT_UInt autohint_snap_stem_height = 0; | |
+ if( ftinf ) autohint_snap_stem_height=ftinf->autohint_snap_stem_height; | |
+ if ( autohint_snap_stem_height > 100 ) | |
+ autohint_snap_stem_height = 100; | |
+ else if ( autohint_snap_stem_height < 0 ) | |
+ autohint_snap_stem_height = 0; | |
- | |
+ if ( autohint_snap_stem_height == 0 ) | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || | |
axis->extra_light ) | |
return width; | |
@@ -2759,9 +2797,76 @@ | |
dist = -width; | |
sign = 1; | |
} | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* Calculate snap value differently than standard freetype */ | |
+ if ( autohint_snap_stem_height > 0 && | |
+ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || | |
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) | |
+ { | |
+ infinality_dist = af_latin_snap_width( axis->widths, | |
+ axis->width_count, dist ); | |
+ | |
+ if ( metrics->root.scaler.face->size->metrics.x_ppem > 9 && | |
+ axis->width_count > 0 && | |
+ abs( axis->widths[0].cur - infinality_dist ) < 32 && | |
+ axis->widths[0].cur > 52 ) | |
+ { | |
+ const char *style_name=metrics->root.scaler.face->style_name; | |
+ if ( style_name!=NULL && | |
+ ( strstr( style_name, "Regular" ) || | |
+ strstr( style_name, "Book" ) || | |
+ strstr( style_name, "Medium" ) || | |
+ strcmp( style_name, "Italic" ) == 0 || | |
+ strcmp( style_name, "Oblique" ) == 0 ) | |
+ ) | |
+ { | |
+ /* regular weight */ | |
+ if ( axis->widths[0].cur < 64 ) | |
+ infinality_dist = 64; | |
+ else if ( axis->widths[0].cur < 88 ) | |
+ infinality_dist = 64; | |
+ else if ( axis->widths[0].cur < 160 ) | |
+ infinality_dist = 128; | |
+ else if ( axis->widths[0].cur < 240 ) | |
+ infinality_dist = 190; | |
+ else infinality_dist = ( infinality_dist ) & ~63; | |
+ } | |
+ else | |
+ { | |
+ /* bold gets a different threshold */ | |
+ if ( axis->widths[0].cur < 64 ) | |
+ infinality_dist = 64 ; | |
+ else if ( axis->widths[0].cur < 108 ) | |
+ infinality_dist = 64; | |
+ else if ( axis->widths[0].cur < 160 ) | |
+ infinality_dist = 128; | |
+ else if ( axis->widths[0].cur < 222 ) | |
+ infinality_dist = 190; | |
+ else if ( axis->widths[0].cur < 288 ) | |
+ infinality_dist = 254; | |
+ else infinality_dist = ( infinality_dist + 16 ) & ~63; | |
+ } | |
+ | |
+ } | |
+ if ( infinality_dist < 52 ) | |
+ { | |
+ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 ) | |
+ { | |
+ if ( infinality_dist < 32 ) | |
+ infinality_dist = 32; | |
+ } | |
+ else | |
+ infinality_dist = 64; | |
+ } | |
+ } | |
+ else if ( autohint_snap_stem_height < 100 && | |
+ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || | |
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) | |
+#else | |
if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || | |
( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
{ | |
/* smooth hinting process: very lightly quantize the stem width */ | |
@@ -2853,6 +2958,9 @@ | |
} | |
} | |
else | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( autohint_snap_stem_height < 100 ) | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
{ | |
/* strong hinting process: snap the stem width to integer pixels */ | |
@@ -2860,7 +2968,10 @@ | |
dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( autohint_snap_stem_height > 0 ) | |
+ goto Done_Width; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
if ( vertical ) | |
{ | |
/* in the case of vertical hinting, always round */ | |
@@ -2923,6 +3034,32 @@ | |
} | |
Done_Width: | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( axis->widths[0].cur > 42 ) | |
+ /* weighted average */ | |
+ dist = (dist * ( 100 - autohint_snap_stem_height ) | |
+ + infinality_dist * autohint_snap_stem_height ) / 100; | |
+ | |
+ { | |
+ int factor = 100; | |
+ if ( axis->standard_width < 100 ) | |
+ factor = axis->standard_width; | |
+ | |
+ if ( metrics->root.scaler.face->size->metrics.x_ppem >= 9 && dist < 52 ) | |
+ dist += ( (52 - dist) * factor ) / 100; | |
+ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 && dist < 32 ) | |
+ dist += ( (32 - dist) * factor ) / 100; | |
+ | |
+ if ( axis->standard_width > 100 && | |
+ metrics->root.scaler.face->size->metrics.x_ppem >= 11 && | |
+ dist < 64 ) | |
+ dist = 64; | |
+ if ( axis->standard_width > 100 && | |
+ metrics->root.scaler.face->size->metrics.x_ppem >= 9 && | |
+ dist < 52 ) | |
+ dist = 52; | |
+ } | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
if ( sign ) | |
dist = -dist; | |
@@ -2941,6 +3078,8 @@ | |
FT_Pos dist, base_delta; | |
FT_Pos fitted_width; | |
+/* if fitted_width causes stem_edge->pos to land basically on top of an existing | |
+ * stem_edge->pos, then add or remove 64. Need to figure out a way to do this */ | |
dist = stem_edge->opos - base_edge->opos; | |
base_delta = base_edge->pos - base_edge->opos; | |
@@ -3548,8 +3687,11 @@ | |
int dim; | |
AF_LatinAxis axis; | |
- | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Int emboldening_strength = 0; | |
+ FT_Bool use_various_tweaks = FALSE; | |
+ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
error = af_glyph_hints_reload( hints, outline ); | |
if ( error ) | |
goto Exit; | |
@@ -3595,7 +3737,11 @@ | |
} | |
af_glyph_hints_save( hints, outline ); | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ { | |
+ infinality_cur_width = metrics->axis->widths[0].cur; | |
+ } | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
Exit: | |
return error; | |
} | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/aflatin.h a/src/autofit/aflatin.h | |
--- b/src/autofit/aflatin.h 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/autofit/aflatin.h 2021-09-16 09:15:05.051379735 +0300 | |
@@ -64,6 +64,9 @@ | |
#define AF_LATIN_MAX_WIDTHS 16 | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ extern FT_Pos infinality_cur_width; | |
+#endif | |
#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ | |
#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/afmodule.c a/src/autofit/afmodule.c | |
--- b/src/autofit/afmodule.c 2021-07-12 15:07:00.000000000 +0300 | |
+++ a/src/autofit/afmodule.c 2021-09-16 09:15:05.051379735 +0300 | |
@@ -21,6 +21,10 @@ | |
#include "afloader.h" | |
#include "aferrors.h" | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "../base/ftinf.h" | |
+#endif | |
+ | |
#ifdef FT_DEBUG_AUTOFIT | |
#ifndef FT_MAKE_OPTION_SINGLE_OBJECT | |
@@ -405,6 +409,9 @@ | |
module->fallback_style = AF_STYLE_FALLBACK; | |
module->default_script = AF_SCRIPT_DEFAULT; | |
module->no_stem_darkening = TRUE; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if(ftinf) module->no_stem_darkening = !ftinf->stem_darkening_autofit; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; | |
module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftbase.c a/src/base/ftbase.c | |
--- b/src/base/ftbase.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/base/ftbase.c 2021-09-16 09:15:05.051379735 +0300 | |
@@ -36,6 +36,9 @@ | |
#include "ftstream.c" | |
#include "fttrigon.c" | |
#include "ftutil.c" | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "ftinf.c" | |
+#endif | |
/* END */ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf.c a/src/base/ftinf.c | |
--- b/src/base/ftinf.c 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf.c 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,363 @@ | |
+#include <stdlib.h> | |
+#include "ftinf.h" | |
+#define true 1 | |
+#define false 0 | |
+ | |
+#define on 1 | |
+#define off 0 | |
+#define end (-128) | |
+ | |
+#define sw2pv 18 /* STEM_WIDTH_2_PPEM */ | |
+#define maxp 100 /* MAX_PPEM */ | |
+ | |
+typedef signed char pv; /* ppm and values type */ | |
+/* the arrays start with existence flag + values */ | |
+typedef struct sa_rules_s { | |
+ const char *name; | |
+ pv always_use_100[1+4+1]; | |
+ pv brightness[1+2+1]; | |
+ pv contrast[1+2+1]; | |
+ pv edge_detection[1+4+1]; | |
+ pv m[1+4+1]; | |
+ pv bearing_correction[1+2+1]; | |
+ pv spacing[1+5+1]; | |
+ pv start[1+5+1]; | |
+ pv stem_scaling[1+6+1]; | |
+ pv stem_translating[1+2+1]; | |
+ pv stem_translating_only[1+10+1]; | |
+ pv stem_widths[1+4]; /* these end with maxp */ | |
+ pv synthesize_stems[1+2+1]; | |
+} sa_rules_t; | |
+ | |
+#pragma GCC diagnostic ignored "-Wpedantic" /* C99 struct initializer tags are needed */ | |
+#pragma GCC diagnostic ignored "-Wunused-function" | |
+ | |
+const ftinf_t *ftinf; | |
+/* final settings, updated from environment */ | |
+ftinf_t _env; | |
+ | |
+/* rules and hashing function */ | |
+#include "ftinf_rh.c" | |
+ | |
+/* rules selection */ | |
+void ftinf_fill_stem_values( Stem_Data *stem_values, | |
+ const char *family, int ppem, int use_known ){ | |
+ /* set the defaults */ | |
+ stem_values->bearing_correction = TRUE; | |
+ stem_values->brightness = 0.0; | |
+ stem_values->contrast = 0.0; | |
+ stem_values->edge_detection = FALSE; | |
+ stem_values->m = -1; | |
+ stem_values->stem_scaling = -1; | |
+ stem_values->stem_spacing = -1; | |
+ stem_values->stem_start = -1; | |
+ stem_values->stem_translating = 0; | |
+ stem_values->stem_translating_only = -1024; | |
+ stem_values->stem_width = -1; | |
+ stem_values->synth_stems = FALSE; | |
+ stem_values->use_100 = FALSE; | |
+ /* pick from known rules if requested and they exist for current family */ | |
+ if( !use_known ) | |
+ return; | |
+ else { | |
+ const sa_rules_t *r=ftinf_rules( family ); | |
+ int i; | |
+ if( r==NULL ) return; | |
+ if( r->stem_widths[0]==on ) | |
+ for( i=1; r->stem_widths[i]!=maxp; ++i ) | |
+ if( ppem < r->stem_widths[i] ){ | |
+ stem_values->stem_width = i-1; | |
+ break; | |
+ } | |
+ | |
+ if( r->stem_scaling[0]==on ) | |
+ for( i=1; r->stem_scaling[i]!=end; i+=2 ) | |
+ if( ppem==r->stem_scaling[i] ){ | |
+ stem_values->stem_scaling = r->stem_scaling[i+1]; | |
+ break; | |
+ } | |
+ | |
+ if( r->m[0]==on ) | |
+ for( i=1; r->m[i]!=end; i+=2 ) | |
+ if( ppem==r->m[i] ){ | |
+ stem_values->m = r->m[i+1]; | |
+ break; | |
+ } | |
+ | |
+ if( r->stem_translating_only[0]==on ) | |
+ for( i=1; r->stem_translating_only[i]!=end; i+=2 ) | |
+ if( ppem==r->stem_translating_only[i] || r->stem_translating_only[i]==0 ){ | |
+ stem_values->stem_translating_only = r->stem_translating_only[i+1]; | |
+ break; | |
+ } | |
+ | |
+ if( r->stem_translating[0]==on ) | |
+ for( i=1; r->stem_translating[i]!=end; i+=2 ) | |
+ if( ppem==r->stem_translating[i] || r->stem_translating[i]==0 ){ | |
+ stem_values->stem_translating = r->stem_translating[i+1]; | |
+ break; | |
+ } | |
+ | |
+ if( r->always_use_100[0]==on ) | |
+ for( i=1; r->always_use_100[i]!=end; i+=2 ) | |
+ if( ppem>=r->always_use_100[i] && ppem<=r->always_use_100[i+1] ){ | |
+ stem_values->use_100 = TRUE; | |
+ break; | |
+ } | |
+ | |
+ if( r->synthesize_stems[0]==on ) | |
+ for( i=1; r->synthesize_stems[i]!=end; i+=2 ) | |
+ if( ppem>=r->synthesize_stems[i] && ppem<=r->synthesize_stems[i+1] ){ | |
+ stem_values->synth_stems = TRUE; | |
+ break; | |
+ } | |
+ | |
+ if( r->edge_detection[0]==on ) | |
+ for( i=1; r->edge_detection[i]!=end; i+=2 ) | |
+ if( ppem>=r->edge_detection[i] && ppem<=r->edge_detection[i+1] ){ | |
+ stem_values->edge_detection = TRUE; | |
+ break; | |
+ } | |
+ | |
+ if( r->bearing_correction[0]==on ) | |
+ for( i=1; r->bearing_correction[i]!=end; i+=2 ) | |
+ if( ppem>=r->bearing_correction[i] && ppem<=r->bearing_correction[i+1] ){ | |
+ stem_values->bearing_correction = FALSE; | |
+ break; | |
+ } | |
+ | |
+#if(0) | |
+ if( r->brightness[0]==on ) | |
+ for( i=1; r->brightness[i]!=end; i+=2 ) | |
+ if( ppem==r->brightness[i]||r->brightness[i]==0 ){ | |
+ stem_values->brightness=r->brightness[i+1]*(1.0f/300.0f); | |
+ break; | |
+ } | |
+ | |
+ if( r->contrast[0]==on ) | |
+ for( i=1; r->contrast[i]!=end; i+=2 ) | |
+ if( ppem==r->contrast[i]||r->contrast[i]==0 ){ | |
+ stem_values->contrast=r->contrast[i+1]*(1.0f/300.0f); | |
+ break; | |
+ } | |
+ if( r->spacing[0]==on ){ | |
+ /* not used by original code */ | |
+ } | |
+ if( r->start[0]==on ){ | |
+ /* not used by original code */ | |
+ } | |
+#endif | |
+ } | |
+ return; | |
+} | |
+ | |
+void ftinf_get_bc( const char *family, int ppem, float *brightness, float *contrast ){ | |
+ const sa_rules_t *r=ftinf_rules( family ); | |
+ *brightness=0; | |
+ *contrast=0; | |
+ if( r ){ | |
+ int i; | |
+ if( r->brightness[0]==on ) | |
+ for( i=1; r->brightness[i]!=end; i+=2 ) | |
+ if( ppem==r->brightness[i]||r->brightness[i]==0 ){ | |
+ *brightness=r->brightness[i+1]*(1.0f/300.0f); | |
+ break; | |
+ } | |
+ | |
+ if( r->contrast[0]==on ) | |
+ for( i=1; r->contrast[i]!=end; i+=2 ) | |
+ if( ppem==r->contrast[i]||r->contrast[i]==0 ){ | |
+ *contrast=r->contrast[i+1]*(1.0f/300.0f); | |
+ break; | |
+ } | |
+ } | |
+ return; | |
+} | |
+ | |
+static int | |
+bool_val( const char *s ){ | |
+ if ( s != NULL ) | |
+ return strcasecmp(s, "true") == 0 | |
+ || strcasecmp(s, "1") == 0 | |
+ || strcasecmp(s, "on") == 0 | |
+ || strcasecmp(s, "yes") ==0; | |
+ else | |
+ return 0; | |
+} | |
+ | |
+static int | |
+int_val( const char *s, int min, int max ){ | |
+ int val; | |
+ sscanf ( s, "%d", &val ); | |
+ if ( val > max ) | |
+ val = max; | |
+ else if ( val < min ) | |
+ val = min; | |
+ return val; | |
+} | |
+ | |
+/* settings and hashing function */ | |
+#include "ftinf_sh.c" | |
+ | |
+/* | |
+ Get active Infinality settings | |
+ */ | |
+void ftinf_env(){ | |
+ const char *s; | |
+ ftinf=ftinf_settings( getenv( "INFINALITY_FT" ) ); | |
+ | |
+ if( ftinf==NULL ){ | |
+ ftinf=ftinf_settings( "ultimate3" ); | |
+ /* this should always succeed */ | |
+#if(0) | |
+ if( ftinf==NULL ){ | |
+ /* put an error here */ | |
+ exit(-1); | |
+ } | |
+#endif | |
+ } | |
+ _env=ftinf[0]; /* copy as defaults */ | |
+ | |
+ /* check if custom environment values are set and update with them */ | |
+ s=getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" ); | |
+ if( s ) _env.autohint_increase_glyph_heights=bool_val( s ); | |
+ s=getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" ); | |
+ if( s ) _env.autohint_snap_stem_height=int_val( s, 0, 100 ); | |
+ s=getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" ); | |
+ if( s ) _env.use_various_tweaks=bool_val( s ); | |
+ s=getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" ); | |
+ if( s ) _env.use_known_settings_on_selected_fonts=bool_val(s); | |
+#if(0) /* not used (naming error also) */ | |
+ s=getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" ); | |
+ if( s ) _env.autohint_minimum_stem_height=int_val( s, 0, 100 ); | |
+#endif | |
+ s=getenv( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" ); | |
+ if( s ) sscanf( s, "%d", &_env.stem_snapping_sliding_scale ); | |
+ s=getenv( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.stem_alignment_strength ); | |
+ s=getenv( "INFINALITY_FT_STEM_DARKENING_AUTOFIT" ); | |
+ if( s ) _env.stem_darkening_autofit=bool_val( s ); | |
+ s=getenv( "INFINALITY_FT_STEM_DARKENING_CFF" ); | |
+ if( s ) _env.stem_darkening_cff=bool_val( s ); | |
+ s=getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.stem_fitting_strength ); | |
+ s=getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" ); | |
+ if( s ) _env.chromeos_style_sharpening_strength=int_val( s, 0, 100 ); | |
+ s=getenv( "INFINALITY_FT_BRIGHTNESS" ); | |
+ if( s ) sscanf( s, "%d", &_env.brightness ); | |
+ s=getenv( "INFINALITY_FT_CONTRAST" ); | |
+ if( s ) sscanf( s, "%d", &_env.contrast ); | |
+ s=getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" ); | |
+ if( s ) _env.windows_style_sharpening_strength=int_val( s, 0, 100 ); | |
+ s=getenv( "INFINALITY_FT_GAMMA_CORRECTION" ); | |
+ if( s ){ | |
+ float *f=_env.gamma_correction; | |
+ sscanf ( s, "%f %f", &f[0], &f[1] ); | |
+ if( f[1] < 1.0f ) f[1]=1.0f; | |
+ } | |
+ s=getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.fringe_filter_strength ); | |
+ s=getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.grayscale_filter_strength ); | |
+ s=getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.autohint_horizontal_stem_darken_strength ); | |
+ s=getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" ); | |
+ if( s ) sscanf( s, "%d", &_env.autohint_vertical_stem_darken_strength ); | |
+ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" ); | |
+ if( s ) sscanf( s, "%d", &_env.global_embolden_x_value ); | |
+ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" ); | |
+ if( s ) sscanf( s, "%d", &_env.global_embolden_y_value ); | |
+ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" ); | |
+ if( s ) sscanf( s, "%d", &_env.bold_embolden_x_value ); | |
+ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" ); | |
+ if( s ) sscanf( s, "%d", &_env.bold_embolden_y_value ); | |
+ s=getenv( "INFINALITY_FT_FILTER_PARAMS" ); | |
+ if( s ) { | |
+ int *f=_env.filter_params; | |
+ if( sscanf( s, "%d %d %d %d %d", f+1, f+2, f+3, f+4, f+5 )==5 ) | |
+ f[0]=on; | |
+ else | |
+ f[0]=off; /* FIXME: put a warning? */ | |
+ } | |
+ /* do the range verifications as in original code */ | |
+ if ( _env.stem_snapping_sliding_scale > maxp ) | |
+ _env.stem_snapping_sliding_scale = 0; | |
+ else if ( _env.stem_snapping_sliding_scale < 0 ) | |
+ _env.stem_snapping_sliding_scale = 0; | |
+ if (_env.stem_snapping_sliding_scale < 11 && | |
+ _env.stem_snapping_sliding_scale > 0 ) | |
+ _env.stem_snapping_sliding_scale = 11; | |
+ | |
+ if ( _env.stem_alignment_strength > 100 ) | |
+ _env.stem_alignment_strength = 100; | |
+ else if ( _env.stem_alignment_strength < 0 ) | |
+ _env.stem_alignment_strength = 0; | |
+ | |
+ if ( _env.stem_fitting_strength > 100 ) | |
+ _env.stem_fitting_strength = 100; | |
+ else if ( _env.stem_fitting_strength < 0 ) | |
+ _env.stem_fitting_strength = 0; | |
+ | |
+ if ( _env.chromeos_style_sharpening_strength > 100 ) | |
+ _env.chromeos_style_sharpening_strength = 100; | |
+ else if ( _env.chromeos_style_sharpening_strength < 0 ) | |
+ _env.chromeos_style_sharpening_strength = 0; | |
+ | |
+ if ( _env.brightness > 100 ) | |
+ _env.brightness = 100; | |
+ else if ( _env.brightness < -100 ) | |
+ _env.brightness = 0; | |
+ | |
+ if ( _env.contrast > 100 ) | |
+ _env.contrast = 100; | |
+ else if ( _env.contrast < -100 ) | |
+ _env.contrast = 0; | |
+ | |
+ if ( _env.windows_style_sharpening_strength > 100 ) | |
+ _env.windows_style_sharpening_strength = 100; | |
+ else if ( _env.windows_style_sharpening_strength < 0 ) | |
+ _env.windows_style_sharpening_strength = 0; | |
+ | |
+ if ( _env.fringe_filter_strength > 100 ) | |
+ _env.fringe_filter_strength = 100; | |
+ else if ( _env.fringe_filter_strength < 0 ) | |
+ _env.fringe_filter_strength = 0; | |
+ | |
+ if ( _env.grayscale_filter_strength > 100 ) | |
+ _env.grayscale_filter_strength = 100; | |
+ else if ( _env.grayscale_filter_strength < 0 ) | |
+ _env.grayscale_filter_strength = 0; | |
+ | |
+ if ( _env.autohint_horizontal_stem_darken_strength > 100 ) | |
+ _env.autohint_horizontal_stem_darken_strength = 100; | |
+ else if ( _env.autohint_horizontal_stem_darken_strength < 0 ) | |
+ _env.autohint_horizontal_stem_darken_strength = 0; | |
+ | |
+ if ( _env.autohint_vertical_stem_darken_strength > 100 ) | |
+ _env.autohint_vertical_stem_darken_strength = 100; | |
+ else if ( _env.autohint_horizontal_stem_darken_strength < 0 ) | |
+ _env.autohint_vertical_stem_darken_strength = 0; | |
+ | |
+ if ( _env.global_embolden_x_value > 128 ) | |
+ _env.global_embolden_x_value = 128; | |
+ else if ( _env.global_embolden_x_value < -128 ) | |
+ _env.global_embolden_x_value = -128; | |
+ | |
+ if ( _env.global_embolden_y_value > 128 ) | |
+ _env.global_embolden_y_value = 128; | |
+ else if ( _env.global_embolden_y_value < -128 ) | |
+ _env.global_embolden_y_value = -128; | |
+ | |
+ if ( _env.bold_embolden_x_value > 128 ) | |
+ _env.bold_embolden_x_value = 128; | |
+ else if (_env.bold_embolden_x_value < -128 ) | |
+ _env.bold_embolden_x_value = -128; | |
+ | |
+ if ( _env.bold_embolden_y_value > 128 ) | |
+ _env.bold_embolden_y_value = 128; | |
+ else if ( _env.bold_embolden_y_value < -128 ) | |
+ _env.bold_embolden_y_value = -128; | |
+ | |
+ /* point to the combined and checked settings */ | |
+ ftinf=&_env; | |
+} | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf.h a/src/base/ftinf.h | |
--- b/src/base/ftinf.h 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf.h 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,66 @@ | |
+#ifndef _FTINF_H_ | |
+#define _FTINF_H_ | |
+/* | |
+ Stem snapping rules | |
+ (base freetype typedefs assumed already included) | |
+ */ | |
+typedef struct | |
+{ | |
+ FT_Int stem_width; | |
+ FT_Int stem_spacing; | |
+ FT_Int stem_start; | |
+ FT_Int stem_scaling; | |
+ FT_Int stem_translating_only; | |
+ FT_Int stem_translating; | |
+ float brightness; | |
+ float contrast; | |
+ FT_Bool use_100; | |
+ FT_Bool synth_stems; | |
+ FT_Bool edge_detection; | |
+ FT_Bool bearing_correction; | |
+ FT_Int m; | |
+} Stem_Data; | |
+ | |
+/* | |
+ Infinality settings | |
+ */ | |
+typedef struct ftinf_s { | |
+ const char *name; | |
+ int autohint_horizontal_stem_darken_strength; | |
+ int autohint_snap_stem_height; | |
+ int autohint_increase_glyph_heights; | |
+ int autohint_vertical_stem_darken_strength; | |
+ int bold_embolden_x_value; | |
+ int bold_embolden_y_value; | |
+ int brightness; | |
+ int chromeos_style_sharpening_strength; | |
+ int contrast; | |
+ int filter_params[6]; /* 1st one used as existence flag */ | |
+ int fringe_filter_strength; | |
+ float gamma_correction[2]; | |
+ int global_embolden_x_value; | |
+ int global_embolden_y_value; | |
+ int grayscale_filter_strength; | |
+ int stem_alignment_strength; | |
+ int stem_darkening_autofit; | |
+ int stem_darkening_cff; | |
+ int stem_fitting_strength; | |
+ int stem_snapping_sliding_scale; | |
+ int use_known_settings_on_selected_fonts; | |
+ int use_various_tweaks; | |
+ int windows_style_sharpening_strength; | |
+} ftinf_t; | |
+ | |
+extern FT_Pos infinality_cur_width; /* defined in aflatin.c */ | |
+ | |
+extern const ftinf_t *ftinf; /* active settings */ | |
+ | |
+extern void ftinf_fill_stem_values( Stem_Data *stem_values, | |
+ const char *family, int ppem, int use_known ); | |
+extern void ftinf_get_bc( const char *family, int ppem, | |
+ float *brightness, float *contrast ); | |
+ | |
+/* get values from environment (FIXME: maybe update with using user files) */ | |
+extern void ftinf_env(); | |
+ | |
+#endif | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_rh.c a/src/base/ftinf_rh.c | |
--- b/src/base/ftinf_rh.c 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf_rh.c 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,626 @@ | |
+/* ANSI-C code produced by gperf version 3.1 */ | |
+/* Command-line: gperf --output-file=ftinf_rh.c ftinf_rh.gperf */ | |
+/* Computed positions: -k'1,$' */ | |
+ | |
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ | |
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ | |
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ | |
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ | |
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ | |
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ | |
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ | |
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ | |
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ | |
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ | |
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ | |
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ | |
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ | |
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ | |
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ | |
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ | |
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ | |
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ | |
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ | |
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ | |
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ | |
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ | |
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) | |
+/* The character set is not based on ISO-646. */ | |
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." | |
+#endif | |
+ | |
+#line 9 "ftinf_rh.gperf" | |
+ | |
+#include <ctype.h> | |
+static const struct sa_rules_s* _rules_get( const char*str, unsigned len ); | |
+/* maximum key range = 82, duplicates = 0 */ | |
+ | |
+#ifdef __GNUC__ | |
+__inline | |
+#else | |
+#ifdef __cplusplus | |
+inline | |
+#endif | |
+#endif | |
+static unsigned int | |
+_rules_hash (register const char *str, register unsigned int len) | |
+{ | |
+ static const unsigned char asso_values[] = | |
+ { | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 0, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 5, 45, 5, | |
+ 35, 25, 35, 35, 50, 45, 85, 85, 0, 25, | |
+ 40, 5, 0, 85, 50, 20, 20, 0, 10, 10, | |
+ 85, 10, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, | |
+ 85, 85, 85, 85, 85, 85 | |
+ }; | |
+ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; | |
+} | |
+ | |
+#ifdef __GNUC__ | |
+__inline | |
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ | |
+__attribute__ ((__gnu_inline__)) | |
+#endif | |
+#endif | |
+const struct sa_rules_s * | |
+_rules_get (register const char *str, register unsigned int len) | |
+{ | |
+ enum | |
+ { | |
+ TOTAL_KEYWORDS = 58, | |
+ MIN_WORD_LENGTH = 3, | |
+ MAX_WORD_LENGTH = 24, | |
+ MIN_HASH_VALUE = 3, | |
+ MAX_HASH_VALUE = 84 | |
+ }; | |
+ | |
+ static const struct sa_rules_s wordlist[] = | |
+ { | |
+#line 15 "ftinf_rh.gperf" | |
+{ .name="---", | |
+ .synthesize_stems={on, 13, 13, end} | |
+}, | |
+#line 253 "ftinf_rh.gperf" | |
+{ .name="ubuntu", | |
+ .always_use_100={on, 12, 13, 15, 15, end} | |
+}, | |
+#line 31 "ftinf_rh.gperf" | |
+{ .name="arial", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .edge_detection={on, 11, 11, 13, 13, end}, | |
+ .spacing={on, 10, 11, 23, 25, 30, end}, | |
+ .start={on, 11, 18, 23, 30, 30, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end} | |
+}, | |
+#line 87 "ftinf_rh.gperf" | |
+{ .name="corbel", | |
+ .stem_translating_only={on, 10, 16, end}, | |
+ .stem_widths={on, 10, 21, maxp} | |
+}, | |
+#line 71 "ftinf_rh.gperf" | |
+{ .name="canwell", | |
+ .stem_scaling={on, 13, 0, end} | |
+}, | |
+#line 216 "ftinf_rh.gperf" | |
+{ .name="pragmata", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 67 "ftinf_rh.gperf" | |
+{ .name="cantarell", | |
+ .stem_translating_only={on, 11, 0, 12, 0, end}, | |
+ .stem_widths={on, 10, 22, maxp,} | |
+}, | |
+#line 39 "ftinf_rh.gperf" | |
+{ .name="arimo", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end} | |
+}, | |
+#line 207 "ftinf_rh.gperf" | |
+{ .name="optima", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end}, | |
+ .stem_scaling={on, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end} | |
+}, | |
+#line 63 "ftinf_rh.gperf" | |
+{ .name="candara", | |
+ .stem_scaling={on, 14, 1, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 16, end} | |
+}, | |
+#line 77 "ftinf_rh.gperf" | |
+{ .name="comfortaa", | |
+ .stem_widths={on, 10, 19, 22, maxp}, | |
+ .stem_scaling={on, 11, 0, end} | |
+}, | |
+#line 161 "ftinf_rh.gperf" | |
+{ .name="liberation mono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 18 "ftinf_rh.gperf" | |
+{ .name="andale mono", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_scaling={on, 11, 1, end}, | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+#line 256 "ftinf_rh.gperf" | |
+{ .name="verdana", | |
+ .always_use_100={on, 0, 14, 16, maxp, end}, | |
+ .stem_scaling={on, 12, 1, 15, 1, end}, | |
+ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end} | |
+}, | |
+#line 74 "ftinf_rh.gperf" | |
+{ .name="century gothic", | |
+ .stem_widths={on, 10, 22, maxp,} | |
+}, | |
+#line 91 "ftinf_rh.gperf" | |
+{ .name="courier new", | |
+ .always_use_100={on, 12, 12, end}, | |
+ .edge_detection={on, 10, 12, end}, | |
+ .m={on, 13, 1, 14, 1, end} | |
+}, | |
+#line 23 "ftinf_rh.gperf" | |
+{ .name="arial narrow", | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+#line 185 "ftinf_rh.gperf" | |
+{ .name="luxi sans", | |
+ .always_use_100={on, 13, 13, end}, | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+#line 225 "ftinf_rh.gperf" | |
+{ .name="samba", | |
+ .stem_scaling={on, 11, 0, end} | |
+}, | |
+#line 233 "ftinf_rh.gperf" | |
+{ .name="tahoma", | |
+ .always_use_100={on, 11, 11, 14, maxp, end}, | |
+ .edge_detection={on, 11, 11, end}, | |
+ .spacing={on, 10, 12, 18, 18, 30, end}, | |
+ .start={on, 14, 17, 30, 100, 100, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end}, | |
+}, | |
+#line 164 "ftinf_rh.gperf" | |
+{ .name="liberation sans narrow", | |
+ .stem_widths={on,10, 22, maxp,} | |
+}, | |
+#line 81 "ftinf_rh.gperf" | |
+{ .name="consolas", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 8, 32, 9, 32, end}, | |
+ .stem_widths={on, 10, 20, maxp,}, | |
+ .stem_scaling={on, 11, 1, end} | |
+}, | |
+#line 203 "ftinf_rh.gperf" | |
+{ .name="open sans", | |
+ .stem_translating_only={on, 10, 16, 9, 16, end}, | |
+ .stem_widths={on, 10, 20, maxp,} | |
+}, | |
+#line 167 "ftinf_rh.gperf" | |
+{ .name="liberation sans", | |
+ .edge_detection={on, 11, 11, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}, | |
+ .stem_widths={on,10, 19, maxp,} | |
+}, | |
+#line 193 "ftinf_rh.gperf" | |
+{ .name="monaco", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 101 "ftinf_rh.gperf" | |
+{ .name="cousine", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 176 "ftinf_rh.gperf" | |
+{ .name="lucida grande", | |
+ .stem_scaling={on, 13, 1, end}, | |
+ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, | |
+ .stem_widths={on, 10, 16, sw2pv, maxp}, | |
+}, | |
+#line 173 "ftinf_rh.gperf" | |
+{ .name="lucida console", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 196 "ftinf_rh.gperf" | |
+{ .name="myriad pro", | |
+ .stem_scaling={on, 14, 1, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end} | |
+}, | |
+#line 26 "ftinf_rh.gperf" | |
+{ .name="arial unicode ms", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} | |
+}, | |
+#line 213 "ftinf_rh.gperf" | |
+{ .name="palatino linotype", | |
+ .edge_detection={on, 0, 100, end} | |
+}, | |
+#line 181 "ftinf_rh.gperf" | |
+{ .name="lucida sans unicode", | |
+ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, | |
+ .stem_widths={on,10, 16, sw2pv, maxp,} | |
+}, | |
+#line 140 "ftinf_rh.gperf" | |
+{ .name="futura", | |
+ .stem_widths={on, 10, 14, sw2pv, maxp,} | |
+}, | |
+#line 147 "ftinf_rh.gperf" | |
+{ .name="georgia", | |
+ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end} | |
+}, | |
+#line 125 "ftinf_rh.gperf" | |
+{ .name="freemono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 200 "ftinf_rh.gperf" | |
+{ .name="nina", | |
+ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end} | |
+}, | |
+#line 121 "ftinf_rh.gperf" | |
+{ .name="essential pragmatapro", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .m={on, 13, 0, 14, 0, end} | |
+}, | |
+#line 247 "ftinf_rh.gperf" | |
+{ .name="trebuchet ms", | |
+ .always_use_100={on, 13, 13, end}, | |
+ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end}, | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+#line 114 "ftinf_rh.gperf" | |
+{ .name="droid sans mono", | |
+ .m={on, 12, 0, end} | |
+}, | |
+#line 104 "ftinf_rh.gperf" | |
+{ .name="dejavu sans mono", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end} | |
+}, | |
+#line 57 "ftinf_rh.gperf" | |
+{ .name="calibri", | |
+ .always_use_100={on, 23, maxp, end}, | |
+ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 15, 0, end}, | |
+ .stem_widths={on, 1, 10, 19, maxp,} | |
+}, | |
+#line 156 "ftinf_rh.gperf" | |
+{ .name="inconsolata", | |
+ .stem_scaling={on, 12, 1, 15, 1, end}, | |
+ .stem_translating_only={on, 10, 24, 9, 32, end}, | |
+ .stem_widths={on, 10, 23, maxp,}, | |
+}, | |
+#line 96 "ftinf_rh.gperf" | |
+{ .name="courier", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .m={on, 13, 1, 14, 1, end}, | |
+ .stem_translating_only={on, 13, 16, 15, 0, end} | |
+}, | |
+#line 128 "ftinf_rh.gperf" | |
+{ .name="freesans", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .edge_detection={on, 11, 11, 13, 13, end}, | |
+ .spacing={on, 10, 12, 18, 18, 30, end}, | |
+ .start={on, 10, 18, 18, 25, 30, end}, | |
+ .stem_scaling={on, 16, 0, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 9, 8, end} | |
+}, | |
+#line 150 "ftinf_rh.gperf" | |
+{ .name="gill sans", | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+#line 117 "ftinf_rh.gperf" | |
+{ .name="droid sans", | |
+ .always_use_100={on, 12, 12, 15, 15, end}, | |
+ .stem_translating_only={on, 8, 16, 9, 16, end} | |
+}, | |
+#line 108 "ftinf_rh.gperf" | |
+{ .name="dejavu sans", | |
+ .always_use_100={on, 10, 14, 16, 17, end}, | |
+ .m={on, 12, 0, end}, | |
+ .stem_scaling={on, 12, 1, end}, | |
+ .stem_translating_only={on, 8, 16, 15, -20, end} | |
+}, | |
+#line 219 "ftinf_rh.gperf" | |
+{ .name="raleway", | |
+ .stem_scaling={on, 15, 0, end} | |
+}, | |
+#line 153 "ftinf_rh.gperf" | |
+{ .name="helvetica cy", | |
+ .stem_widths={on, 10, 23, maxp,} | |
+}, | |
+#line 228 "ftinf_rh.gperf" | |
+{ .name="segoe ui", | |
+ .always_use_100={on, 11, 12, 14, 14, end}, | |
+ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end}, | |
+ .stem_widths={on, 10, 23, maxp,} | |
+}, | |
+#line 48 "ftinf_rh.gperf" | |
+{ .name="bitstream vera sans mono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+#line 241 "ftinf_rh.gperf" | |
+{ .name="times new roman", | |
+ .always_use_100={on, 14, 14, 16, 16, end}, | |
+ .bearing_correction={0, 100, end}, | |
+ .stem_scaling={on, 17, 1, end}, | |
+ .stem_translating_only={on, 17, 8, end} | |
+}, | |
+#line 222 "ftinf_rh.gperf" | |
+{ .name="rokkitt", | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+#line 143 "ftinf_rh.gperf" | |
+{ .name="garamond", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end} | |
+}, | |
+#line 137 "ftinf_rh.gperf" | |
+{ .name="freeserif", | |
+ .stem_scaling={on, 13, 1, 17, 1, end} | |
+}, | |
+#line 189 "ftinf_rh.gperf" | |
+{ .name="microsoft sans serif", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} | |
+}, | |
+#line 44 "ftinf_rh.gperf" | |
+{ .name="baskerville", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end} | |
+}, | |
+#line 51 "ftinf_rh.gperf" | |
+{ .name="bitstream vera sans", | |
+ .always_use_100={on, 10, 14, 16, 17, end}, | |
+ .m={on, 12, 0, end}, | |
+ .stem_scaling={on ,12, 1, end}, | |
+ .stem_translating_only={on, 8, 16, end} | |
+} | |
+ }; | |
+ | |
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) | |
+ { | |
+ register int key = _rules_hash (str, len); | |
+ | |
+ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE) | |
+ { | |
+ register const struct sa_rules_s *resword; | |
+ | |
+ switch (key - 3) | |
+ { | |
+ case 0: | |
+ resword = &wordlist[0]; | |
+ goto compare; | |
+ case 3: | |
+ resword = &wordlist[1]; | |
+ goto compare; | |
+ case 7: | |
+ resword = &wordlist[2]; | |
+ goto compare; | |
+ case 8: | |
+ resword = &wordlist[3]; | |
+ goto compare; | |
+ case 9: | |
+ resword = &wordlist[4]; | |
+ goto compare; | |
+ case 10: | |
+ resword = &wordlist[5]; | |
+ goto compare; | |
+ case 11: | |
+ resword = &wordlist[6]; | |
+ goto compare; | |
+ case 12: | |
+ resword = &wordlist[7]; | |
+ goto compare; | |
+ case 13: | |
+ resword = &wordlist[8]; | |
+ goto compare; | |
+ case 14: | |
+ resword = &wordlist[9]; | |
+ goto compare; | |
+ case 16: | |
+ resword = &wordlist[10]; | |
+ goto compare; | |
+ case 17: | |
+ resword = &wordlist[11]; | |
+ goto compare; | |
+ case 18: | |
+ resword = &wordlist[12]; | |
+ goto compare; | |
+ case 19: | |
+ resword = &wordlist[13]; | |
+ goto compare; | |
+ case 21: | |
+ resword = &wordlist[14]; | |
+ goto compare; | |
+ case 23: | |
+ resword = &wordlist[15]; | |
+ goto compare; | |
+ case 24: | |
+ resword = &wordlist[16]; | |
+ goto compare; | |
+ case 26: | |
+ resword = &wordlist[17]; | |
+ goto compare; | |
+ case 27: | |
+ resword = &wordlist[18]; | |
+ goto compare; | |
+ case 28: | |
+ resword = &wordlist[19]; | |
+ goto compare; | |
+ case 29: | |
+ resword = &wordlist[20]; | |
+ goto compare; | |
+ case 30: | |
+ resword = &wordlist[21]; | |
+ goto compare; | |
+ case 31: | |
+ resword = &wordlist[22]; | |
+ goto compare; | |
+ case 32: | |
+ resword = &wordlist[23]; | |
+ goto compare; | |
+ case 33: | |
+ resword = &wordlist[24]; | |
+ goto compare; | |
+ case 34: | |
+ resword = &wordlist[25]; | |
+ goto compare; | |
+ case 35: | |
+ resword = &wordlist[26]; | |
+ goto compare; | |
+ case 36: | |
+ resword = &wordlist[27]; | |
+ goto compare; | |
+ case 37: | |
+ resword = &wordlist[28]; | |
+ goto compare; | |
+ case 38: | |
+ resword = &wordlist[29]; | |
+ goto compare; | |
+ case 39: | |
+ resword = &wordlist[30]; | |
+ goto compare; | |
+ case 41: | |
+ resword = &wordlist[31]; | |
+ goto compare; | |
+ case 43: | |
+ resword = &wordlist[32]; | |
+ goto compare; | |
+ case 44: | |
+ resword = &wordlist[33]; | |
+ goto compare; | |
+ case 45: | |
+ resword = &wordlist[34]; | |
+ goto compare; | |
+ case 46: | |
+ resword = &wordlist[35]; | |
+ goto compare; | |
+ case 48: | |
+ resword = &wordlist[36]; | |
+ goto compare; | |
+ case 49: | |
+ resword = &wordlist[37]; | |
+ goto compare; | |
+ case 52: | |
+ resword = &wordlist[38]; | |
+ goto compare; | |
+ case 53: | |
+ resword = &wordlist[39]; | |
+ goto compare; | |
+ case 54: | |
+ resword = &wordlist[40]; | |
+ goto compare; | |
+ case 58: | |
+ resword = &wordlist[41]; | |
+ goto compare; | |
+ case 59: | |
+ resword = &wordlist[42]; | |
+ goto compare; | |
+ case 60: | |
+ resword = &wordlist[43]; | |
+ goto compare; | |
+ case 61: | |
+ resword = &wordlist[44]; | |
+ goto compare; | |
+ case 62: | |
+ resword = &wordlist[45]; | |
+ goto compare; | |
+ case 63: | |
+ resword = &wordlist[46]; | |
+ goto compare; | |
+ case 64: | |
+ resword = &wordlist[47]; | |
+ goto compare; | |
+ case 69: | |
+ resword = &wordlist[48]; | |
+ goto compare; | |
+ case 70: | |
+ resword = &wordlist[49]; | |
+ goto compare; | |
+ case 71: | |
+ resword = &wordlist[50]; | |
+ goto compare; | |
+ case 72: | |
+ resword = &wordlist[51]; | |
+ goto compare; | |
+ case 74: | |
+ resword = &wordlist[52]; | |
+ goto compare; | |
+ case 75: | |
+ resword = &wordlist[53]; | |
+ goto compare; | |
+ case 76: | |
+ resword = &wordlist[54]; | |
+ goto compare; | |
+ case 77: | |
+ resword = &wordlist[55]; | |
+ goto compare; | |
+ case 78: | |
+ resword = &wordlist[56]; | |
+ goto compare; | |
+ case 81: | |
+ resword = &wordlist[57]; | |
+ goto compare; | |
+ } | |
+ return 0; | |
+ compare: | |
+ { | |
+ register const char *s = resword->name; | |
+ | |
+ if (*str == *s && !strcmp (str + 1, s + 1)) | |
+ return resword; | |
+ } | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+#line 261 "ftinf_rh.gperf" | |
+ | |
+ | |
+static const sa_rules_t* | |
+ftinf_rules( const char *name ){ | |
+ if( name ){ | |
+ enum { | |
+ max_wlen=31 | |
+ }; | |
+ char buf[max_wlen+1]; | |
+ int len=strlen( name ); | |
+ if( len <= max_wlen ){ | |
+ int i; | |
+ for( i=0; i<len; ++i ) | |
+ buf[i]=tolower( name[i] ); | |
+ buf[len]='\0'; | |
+ return _rules_get( buf, len ); | |
+ } | |
+ } | |
+ return NULL; | |
+} | |
+/* | |
+ gperf --output-file=ftinf_rh.c ftinf_rh.gperf | |
+*/ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_rh.gperf a/src/base/ftinf_rh.gperf | |
--- b/src/base/ftinf_rh.gperf 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf_rh.gperf 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,283 @@ | |
+%struct-type | |
+%define slot-name name | |
+%enum | |
+%switch=1 | |
+%readonly-tables | |
+%omit-struct-type | |
+%define lookup-function-name _rules_get | |
+%define hash-function-name _rules_hash | |
+%{ | |
+#include <ctype.h> | |
+static const struct sa_rules_s* _rules_get( const char*str, unsigned len ); | |
+%} | |
+struct sa_rules_s; | |
+%% | |
+{ .name="---", | |
+ .synthesize_stems={on, 13, 13, end} | |
+}, | |
+{ .name="andale mono", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_scaling={on, 11, 1, end}, | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+{ .name="arial narrow", | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+{ .name="arial unicode ms", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} | |
+}, | |
+{ .name="arial", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .edge_detection={on, 11, 11, 13, 13, end}, | |
+ .spacing={on, 10, 11, 23, 25, 30, end}, | |
+ .start={on, 11, 18, 23, 30, 30, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end} | |
+}, | |
+{ .name="arimo", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end} | |
+}, | |
+{ .name="baskerville", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end} | |
+}, | |
+{ .name="bitstream vera sans mono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="bitstream vera sans", | |
+ .always_use_100={on, 10, 14, 16, 17, end}, | |
+ .m={on, 12, 0, end}, | |
+ .stem_scaling={on ,12, 1, end}, | |
+ .stem_translating_only={on, 8, 16, end} | |
+}, | |
+{ .name="calibri", | |
+ .always_use_100={on, 23, maxp, end}, | |
+ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 15, 0, end}, | |
+ .stem_widths={on, 1, 10, 19, maxp,} | |
+}, | |
+{ .name="candara", | |
+ .stem_scaling={on, 14, 1, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 16, end} | |
+}, | |
+{ .name="cantarell", | |
+ .stem_translating_only={on, 11, 0, 12, 0, end}, | |
+ .stem_widths={on, 10, 22, maxp,} | |
+}, | |
+{ .name="canwell", | |
+ .stem_scaling={on, 13, 0, end} | |
+}, | |
+{ .name="century gothic", | |
+ .stem_widths={on, 10, 22, maxp,} | |
+}, | |
+{ .name="comfortaa", | |
+ .stem_widths={on, 10, 19, 22, maxp}, | |
+ .stem_scaling={on, 11, 0, end} | |
+}, | |
+{ .name="consolas", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 8, 32, 9, 32, end}, | |
+ .stem_widths={on, 10, 20, maxp,}, | |
+ .stem_scaling={on, 11, 1, end} | |
+}, | |
+{ .name="corbel", | |
+ .stem_translating_only={on, 10, 16, end}, | |
+ .stem_widths={on, 10, 21, maxp} | |
+}, | |
+{ .name="courier new", | |
+ .always_use_100={on, 12, 12, end}, | |
+ .edge_detection={on, 10, 12, end}, | |
+ .m={on, 13, 1, 14, 1, end} | |
+}, | |
+{ .name="courier", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .m={on, 13, 1, 14, 1, end}, | |
+ .stem_translating_only={on, 13, 16, 15, 0, end} | |
+}, | |
+{ .name="cousine", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="dejavu sans mono", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end} | |
+}, | |
+{ .name="dejavu sans", | |
+ .always_use_100={on, 10, 14, 16, 17, end}, | |
+ .m={on, 12, 0, end}, | |
+ .stem_scaling={on, 12, 1, end}, | |
+ .stem_translating_only={on, 8, 16, 15, -20, end} | |
+}, | |
+{ .name="droid sans mono", | |
+ .m={on, 12, 0, end} | |
+}, | |
+{ .name="droid sans", | |
+ .always_use_100={on, 12, 12, 15, 15, end}, | |
+ .stem_translating_only={on, 8, 16, 9, 16, end} | |
+}, | |
+{ .name="essential pragmatapro", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .m={on, 13, 0, 14, 0, end} | |
+}, | |
+{ .name="freemono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="freesans", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .edge_detection={on, 11, 11, 13, 13, end}, | |
+ .spacing={on, 10, 12, 18, 18, 30, end}, | |
+ .start={on, 10, 18, 18, 25, 30, end}, | |
+ .stem_scaling={on, 16, 0, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 16, 9, 8, end} | |
+}, | |
+{ .name="freeserif", | |
+ .stem_scaling={on, 13, 1, 17, 1, end} | |
+}, | |
+{ .name="futura", | |
+ .stem_widths={on, 10, 14, sw2pv, maxp,} | |
+}, | |
+{ .name="garamond", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end} | |
+}, | |
+{ .name="georgia", | |
+ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end} | |
+}, | |
+{ .name="gill sans", | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+{ .name="helvetica cy", | |
+ .stem_widths={on, 10, 23, maxp,} | |
+}, | |
+{ .name="inconsolata", | |
+ .stem_scaling={on, 12, 1, 15, 1, end}, | |
+ .stem_translating_only={on, 10, 24, 9, 32, end}, | |
+ .stem_widths={on, 10, 23, maxp,}, | |
+}, | |
+{ .name="liberation mono", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="liberation sans narrow", | |
+ .stem_widths={on,10, 22, maxp,} | |
+}, | |
+{ .name="liberation sans", | |
+ .edge_detection={on, 11, 11, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}, | |
+ .stem_widths={on,10, 19, maxp,} | |
+}, | |
+{ .name="lucida console", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="lucida grande", | |
+ .stem_scaling={on, 13, 1, end}, | |
+ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, | |
+ .stem_widths={on, 10, 16, sw2pv, maxp}, | |
+}, | |
+{ .name="lucida sans unicode", | |
+ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, | |
+ .stem_widths={on,10, 16, sw2pv, maxp,} | |
+}, | |
+{ .name="luxi sans", | |
+ .always_use_100={on, 13, 13, end}, | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+{ .name="microsoft sans serif", | |
+ .always_use_100={on, 0, maxp, end}, | |
+ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} | |
+}, | |
+{ .name="monaco", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="myriad pro", | |
+ .stem_scaling={on, 14, 1, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end} | |
+}, | |
+{ .name="nina", | |
+ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end} | |
+}, | |
+{ .name="open sans", | |
+ .stem_translating_only={on, 10, 16, 9, 16, end}, | |
+ .stem_widths={on, 10, 20, maxp,} | |
+}, | |
+{ .name="optima", | |
+ .brightness={on, 0, -20, end}, | |
+ .contrast={on, 0, 25, end}, | |
+ .stem_scaling={on, 17, 1, end}, | |
+ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end} | |
+}, | |
+{ .name="palatino linotype", | |
+ .edge_detection={on, 0, 100, end} | |
+}, | |
+{ .name="pragmata", | |
+ .always_use_100={on, 0, maxp, end} | |
+}, | |
+{ .name="raleway", | |
+ .stem_scaling={on, 15, 0, end} | |
+}, | |
+{ .name="rokkitt", | |
+ .stem_widths={on, 10, 21, maxp,} | |
+}, | |
+{ .name="samba", | |
+ .stem_scaling={on, 11, 0, end} | |
+}, | |
+{ .name="segoe ui", | |
+ .always_use_100={on, 11, 12, 14, 14, end}, | |
+ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end}, | |
+ .stem_widths={on, 10, 23, maxp,} | |
+}, | |
+{ .name="tahoma", | |
+ .always_use_100={on, 11, 11, 14, maxp, end}, | |
+ .edge_detection={on, 11, 11, end}, | |
+ .spacing={on, 10, 12, 18, 18, 30, end}, | |
+ .start={on, 14, 17, 30, 100, 100, end}, | |
+ .stem_translating={on, 11, 32, end}, | |
+ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end}, | |
+}, | |
+{ .name="times new roman", | |
+ .always_use_100={on, 14, 14, 16, 16, end}, | |
+ .bearing_correction={0, 100, end}, | |
+ .stem_scaling={on, 17, 1, end}, | |
+ .stem_translating_only={on, 17, 8, end} | |
+}, | |
+{ .name="trebuchet ms", | |
+ .always_use_100={on, 13, 13, end}, | |
+ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end}, | |
+ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end}, | |
+ .stem_widths={on, 10, 17, sw2pv, maxp,} | |
+}, | |
+{ .name="ubuntu", | |
+ .always_use_100={on, 12, 13, 15, 15, end} | |
+}, | |
+{ .name="verdana", | |
+ .always_use_100={on, 0, 14, 16, maxp, end}, | |
+ .stem_scaling={on, 12, 1, 15, 1, end}, | |
+ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end} | |
+}, | |
+%% | |
+ | |
+static const sa_rules_t* | |
+ftinf_rules( const char *name ){ | |
+ if( name ){ | |
+ enum { | |
+ max_wlen=31 | |
+ }; | |
+ char buf[max_wlen+1]; | |
+ int len=strlen( name ); | |
+ if( len <= max_wlen ){ | |
+ int i; | |
+ for( i=0; i<len; ++i ) | |
+ buf[i]=tolower( name[i] ); | |
+ buf[len]='\0'; | |
+ return _rules_get( buf, len ); | |
+ } | |
+ } | |
+ return NULL; | |
+} | |
+/* | |
+ gperf --output-file=ftinf_rh.c ftinf_rh.gperf | |
+*/ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_sh.c a/src/base/ftinf_sh.c | |
--- b/src/base/ftinf_sh.c 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf_sh.c 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,463 @@ | |
+/* ANSI-C code produced by gperf version 3.1 */ | |
+/* Command-line: gperf --output-file=ftinf_sh.c ftinf_sh.gperf */ | |
+/* Computed positions: -k'1,$' */ | |
+ | |
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ | |
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ | |
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ | |
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ | |
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ | |
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ | |
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ | |
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ | |
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ | |
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ | |
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ | |
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ | |
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ | |
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ | |
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ | |
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ | |
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ | |
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ | |
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ | |
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ | |
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ | |
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ | |
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) | |
+/* The character set is not based on ISO-646. */ | |
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." | |
+#endif | |
+ | |
+#line 9 "ftinf_sh.gperf" | |
+ | |
+#include <ctype.h> | |
+static const struct ftinf_s* _settings_get( const char*str, unsigned len); | |
+/* maximum key range = 37, duplicates = 0 */ | |
+ | |
+#ifdef __GNUC__ | |
+__inline | |
+#else | |
+#ifdef __cplusplus | |
+inline | |
+#endif | |
+#endif | |
+static unsigned int | |
+_settings_hash (register const char *str, register unsigned int len) | |
+{ | |
+ static const unsigned char asso_values[] = | |
+ { | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 13, | |
+ 8, 30, 25, 20, 40, 10, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 5, 40, 0, | |
+ 0, 0, 40, 40, 10, 0, 40, 40, 15, 5, | |
+ 10, 0, 10, 40, 40, 0, 0, 0, 0, 0, | |
+ 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, | |
+ 40, 40, 40, 40, 40, 40 | |
+ }; | |
+ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; | |
+} | |
+ | |
+#ifdef __GNUC__ | |
+__inline | |
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ | |
+__attribute__ ((__gnu_inline__)) | |
+#endif | |
+#endif | |
+const struct ftinf_s * | |
+_settings_get (register const char *str, register unsigned int len) | |
+{ | |
+ enum | |
+ { | |
+ TOTAL_KEYWORDS = 22, | |
+ MIN_WORD_LENGTH = 3, | |
+ MAX_WORD_LENGTH = 14, | |
+ MIN_HASH_VALUE = 3, | |
+ MAX_HASH_VALUE = 39 | |
+ }; | |
+ | |
+ static const struct ftinf_s wordlist[] = | |
+ { | |
+#line 76 "ftinf_sh.gperf" | |
+{ .name="osx", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .bold_embolden_x_value=16, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .filter_params={on, 3, 32, 38, 32, 3}, | |
+ .gamma_correction={1000, 80}, | |
+ .global_embolden_y_value=8, | |
+ .grayscale_filter_strength=25, | |
+}, | |
+#line 37 "ftinf_sh.gperf" | |
+{ .name="ipad", | |
+ .filter_params={on, 0, 0, 100, 0, 0}, | |
+ .gamma_correction={1000, 80}, | |
+ .grayscale_filter_strength=100 | |
+}, | |
+#line 114 "ftinf_sh.gperf" | |
+{ .name="shove", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=100, | |
+ .stem_fitting_strength=100, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 126 "ftinf_sh.gperf" | |
+{ .name="ubuntu", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=-10, | |
+ .contrast=15, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={1000, 80}, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 27 "ftinf_sh.gperf" | |
+{ .name="classic", | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .filter_params={on, 6, 25, 38, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 34 "ftinf_sh.gperf" | |
+{ .name="disabled", | |
+ .gamma_correction={0, 100}, | |
+}, | |
+#line 100 "ftinf_sh.gperf" | |
+{ .name="sharpened", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=25, | |
+ .stem_snapping_sliding_scale=40, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+#line 42 "ftinf_sh.gperf" | |
+{ .name="infinality", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=25, | |
+ .stem_snapping_sliding_scale=40, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=5 | |
+}, | |
+#line 15 "ftinf_sh.gperf" | |
+{ .name="custom", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 8, 24, 48, 24, 8}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=75, | |
+ .stem_fitting_strength=50, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 180 "ftinf_sh.gperf" | |
+{ .name="vanilla", | |
+ .filter_params={on, 6, 25, 38, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+}, | |
+#line 184 "ftinf_sh.gperf" | |
+{ .name="windows7light", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .contrast=20, | |
+ .filter_params={on, 20, 25, 38, 25, 05}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 160}, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=100 | |
+}, | |
+#line 226 "ftinf_sh.gperf" | |
+{ .name="windowsxplight", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=20, | |
+ .contrast=30, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 120}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+#line 64 "ftinf_sh.gperf" | |
+{ .name="nudge", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_various_tweaks=true, | |
+}, | |
+#line 144 "ftinf_sh.gperf" | |
+{ .name="ultimate2", | |
+ .filter_params={on, 6, 22, 36, 22, 6}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+#line 197 "ftinf_sh.gperf" | |
+{ .name="windows7", | |
+ .filter_params={on, 20, 25, 42, 25, 06}, | |
+ .fringe_filter_strength=100, | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .windows_style_sharpening_strength=65, | |
+ .gamma_correction={1000, 120}, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .use_various_tweaks=true, | |
+ .autohint_snap_stem_height=100, | |
+ .use_known_settings_on_selected_fonts=true, | |
+}, | |
+#line 210 "ftinf_sh.gperf" | |
+{ .name="windowsxp", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 120}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+#line 56 "ftinf_sh.gperf" | |
+{ .name="linux", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 135 "ftinf_sh.gperf" | |
+{ .name="ultimate1", | |
+ .filter_params={on, 4, 22, 38, 22, 4}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+#line 87 "ftinf_sh.gperf" | |
+{ .name="push", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=75, | |
+ .stem_fitting_strength=50, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+#line 171 "ftinf_sh.gperf" | |
+{ .name="ultimate5", | |
+ .filter_params={on, 12, 28, 42, 28, 12}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+#line 162 "ftinf_sh.gperf" | |
+{ .name="ultimate4", | |
+ .filter_params={on, 10, 25, 37, 25, 10}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+#line 153 "ftinf_sh.gperf" | |
+{ .name="ultimate3", | |
+ .filter_params={on, 8, 24, 36, 24, 8}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+} | |
+ }; | |
+ | |
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) | |
+ { | |
+ register int key = _settings_hash (str, len); | |
+ | |
+ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE) | |
+ { | |
+ register const struct ftinf_s *resword; | |
+ | |
+ switch (key - 3) | |
+ { | |
+ case 0: | |
+ resword = &wordlist[0]; | |
+ goto compare; | |
+ case 1: | |
+ resword = &wordlist[1]; | |
+ goto compare; | |
+ case 2: | |
+ resword = &wordlist[2]; | |
+ goto compare; | |
+ case 3: | |
+ resword = &wordlist[3]; | |
+ goto compare; | |
+ case 4: | |
+ resword = &wordlist[4]; | |
+ goto compare; | |
+ case 5: | |
+ resword = &wordlist[5]; | |
+ goto compare; | |
+ case 6: | |
+ resword = &wordlist[6]; | |
+ goto compare; | |
+ case 7: | |
+ resword = &wordlist[7]; | |
+ goto compare; | |
+ case 8: | |
+ resword = &wordlist[8]; | |
+ goto compare; | |
+ case 9: | |
+ resword = &wordlist[9]; | |
+ goto compare; | |
+ case 10: | |
+ resword = &wordlist[10]; | |
+ goto compare; | |
+ case 11: | |
+ resword = &wordlist[11]; | |
+ goto compare; | |
+ case 12: | |
+ resword = &wordlist[12]; | |
+ goto compare; | |
+ case 14: | |
+ resword = &wordlist[13]; | |
+ goto compare; | |
+ case 15: | |
+ resword = &wordlist[14]; | |
+ goto compare; | |
+ case 16: | |
+ resword = &wordlist[15]; | |
+ goto compare; | |
+ case 17: | |
+ resword = &wordlist[16]; | |
+ goto compare; | |
+ case 19: | |
+ resword = &wordlist[17]; | |
+ goto compare; | |
+ case 21: | |
+ resword = &wordlist[18]; | |
+ goto compare; | |
+ case 26: | |
+ resword = &wordlist[19]; | |
+ goto compare; | |
+ case 31: | |
+ resword = &wordlist[20]; | |
+ goto compare; | |
+ case 36: | |
+ resword = &wordlist[21]; | |
+ goto compare; | |
+ } | |
+ return 0; | |
+ compare: | |
+ { | |
+ register const char *s = resword->name; | |
+ | |
+ if (*str == *s && !strcmp (str + 1, s + 1)) | |
+ return resword; | |
+ } | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+#line 242 "ftinf_sh.gperf" | |
+ | |
+ | |
+static const ftinf_t* | |
+ftinf_settings( const char *name ){ | |
+ if( name ){ | |
+ enum { | |
+ max_wlen=31 | |
+ }; | |
+ char buf[max_wlen+1]; | |
+ int len=strlen( name ); | |
+ if( len <= max_wlen ){ | |
+ int i; | |
+ for( i=0; i<len; ++i ) | |
+ buf[i]=tolower( name[i] ); | |
+ buf[len]='\0'; | |
+ return _settings_get( buf, len ); | |
+ } | |
+ } | |
+ return NULL; | |
+} | |
+/* | |
+ gperf --output-file=ftinf_sh.c ftinf_sh.gperf | |
+*/ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_sh.gperf a/src/base/ftinf_sh.gperf | |
--- b/src/base/ftinf_sh.gperf 1970-01-01 03:00:00.000000000 +0300 | |
+++ a/src/base/ftinf_sh.gperf 2021-09-16 09:15:05.052379743 +0300 | |
@@ -0,0 +1,264 @@ | |
+%struct-type | |
+%define slot-name name | |
+%enum | |
+%switch=1 | |
+%readonly-tables | |
+%omit-struct-type | |
+%define lookup-function-name _settings_get | |
+%define hash-function-name _settings_hash | |
+%{ | |
+#include <ctype.h> | |
+static const struct ftinf_s* _settings_get( const char*str, unsigned len); | |
+%} | |
+struct ftinf_s; | |
+%% | |
+{ .name="custom", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 8, 24, 48, 24, 8}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=75, | |
+ .stem_fitting_strength=50, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="classic", | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .filter_params={on, 6, 25, 38, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="disabled", | |
+ .gamma_correction={0, 100}, | |
+}, | |
+{ .name="ipad", | |
+ .filter_params={on, 0, 0, 100, 0, 0}, | |
+ .gamma_correction={1000, 80}, | |
+ .grayscale_filter_strength=100 | |
+}, | |
+{ .name="infinality", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=25, | |
+ .stem_snapping_sliding_scale=40, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=5 | |
+}, | |
+{ .name="linux", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="nudge", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_various_tweaks=true, | |
+}, | |
+{ .name="osx", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .bold_embolden_x_value=16, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .filter_params={on, 3, 32, 38, 32, 3}, | |
+ .gamma_correction={1000, 80}, | |
+ .global_embolden_y_value=8, | |
+ .grayscale_filter_strength=25, | |
+}, | |
+{ .name="push", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=75, | |
+ .stem_fitting_strength=50, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="sharpened", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=25, | |
+ .stem_fitting_strength=25, | |
+ .stem_snapping_sliding_scale=40, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+{ .name="shove", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_increase_glyph_heights=true, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=100, | |
+ .stem_fitting_strength=100, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="ubuntu", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=-10, | |
+ .contrast=15, | |
+ .filter_params={on, 11, 22, 38, 22, 11}, | |
+ .gamma_correction={1000, 80}, | |
+ .use_various_tweaks=true | |
+}, | |
+{ .name="ultimate1", | |
+ .filter_params={on, 4, 22, 38, 22, 4}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+{ .name="ultimate2", | |
+ .filter_params={on, 6, 22, 36, 22, 6}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+{ .name="ultimate3", | |
+ .filter_params={on, 8, 24, 36, 24, 8}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+{ .name="ultimate4", | |
+ .filter_params={on, 10, 25, 37, 25, 10}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+{ .name="ultimate5", | |
+ .filter_params={on, 12, 28, 42, 28, 12}, | |
+ .fringe_filter_strength=25, | |
+ .gamma_correction={0, 100}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=25 | |
+}, | |
+{ .name="vanilla", | |
+ .filter_params={on, 6, 25, 38, 25, 6}, | |
+ .gamma_correction={0, 100}, | |
+}, | |
+{ .name="windows7light", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .contrast=20, | |
+ .filter_params={on, 20, 25, 38, 25, 05}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 160}, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=100 | |
+}, | |
+{ .name="windows7", | |
+ .filter_params={on, 20, 25, 42, 25, 06}, | |
+ .fringe_filter_strength=100, | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .windows_style_sharpening_strength=65, | |
+ .gamma_correction={1000, 120}, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .use_various_tweaks=true, | |
+ .autohint_snap_stem_height=100, | |
+ .use_known_settings_on_selected_fonts=true, | |
+}, | |
+{ .name="windowsxp", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=10, | |
+ .contrast=20, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 120}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+{ .name="windowsxplight", | |
+ .autohint_horizontal_stem_darken_strength=10, | |
+ .autohint_snap_stem_height=100, | |
+ .autohint_vertical_stem_darken_strength=25, | |
+ .brightness=20, | |
+ .contrast=30, | |
+ .filter_params={on, 6, 25, 44, 25, 6}, | |
+ .fringe_filter_strength=100, | |
+ .gamma_correction={1000, 120}, | |
+ .stem_alignment_strength=15, | |
+ .stem_fitting_strength=15, | |
+ .stem_snapping_sliding_scale=30, | |
+ .use_known_settings_on_selected_fonts=true, | |
+ .use_various_tweaks=true, | |
+ .windows_style_sharpening_strength=65 | |
+}, | |
+%% | |
+ | |
+static const ftinf_t* | |
+ftinf_settings( const char *name ){ | |
+ if( name ){ | |
+ enum { | |
+ max_wlen=31 | |
+ }; | |
+ char buf[max_wlen+1]; | |
+ int len=strlen( name ); | |
+ if( len <= max_wlen ){ | |
+ int i; | |
+ for( i=0; i<len; ++i ) | |
+ buf[i]=tolower( name[i] ); | |
+ buf[len]='\0'; | |
+ return _settings_get( buf, len ); | |
+ } | |
+ } | |
+ return NULL; | |
+} | |
+/* | |
+ gperf --output-file=ftinf_sh.c ftinf_sh.gperf | |
+*/ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinit.c a/src/base/ftinit.c | |
--- b/src/base/ftinit.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/base/ftinit.c 2021-09-16 09:15:05.052379743 +0300 | |
@@ -43,6 +43,10 @@ | |
#include <freetype/internal/ftdebug.h> | |
#include <freetype/ftmodapi.h> | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "ftinf.h" | |
+#endif | |
+ | |
/************************************************************************** | |
* | |
@@ -224,10 +228,14 @@ | |
error = FT_New_Library( memory, alibrary ); | |
if ( error ) | |
FT_Done_Memory( memory ); | |
- else | |
+ else { | |
FT_Add_Default_Modules( *alibrary ); | |
- | |
FT_Set_Default_Properties( *alibrary ); | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* get Infinality settings */ | |
+ ftinf_env(); | |
+#endif | |
+ } | |
return error; | |
} | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftlcdfil.c a/src/base/ftlcdfil.c | |
--- b/src/base/ftlcdfil.c 2021-07-05 06:41:53.000000000 +0300 | |
+++ a/src/base/ftlcdfil.c 2021-09-16 09:15:05.052379743 +0300 | |
@@ -17,11 +17,15 @@ | |
#include <freetype/internal/ftdebug.h> | |
- | |
#include <freetype/ftlcdfil.h> | |
#include <freetype/ftimage.h> | |
#include <freetype/internal/ftobjs.h> | |
+#include <math.h> | |
+#include <string.h> | |
+#include <strings.h> | |
+#include "ftinf.h" | |
+ | |
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
@@ -76,13 +80,13 @@ | |
/* FIR filter used by the default and light filters */ | |
FT_BASE_DEF( void ) | |
ft_lcd_filter_fir( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
FT_LcdFiveTapFilter weights ) | |
{ | |
FT_UInt width = (FT_UInt)bitmap->width; | |
FT_UInt height = (FT_UInt)bitmap->rows; | |
FT_Int pitch = bitmap->pitch; | |
FT_Byte* origin = bitmap->buffer; | |
- FT_Byte mode = bitmap->pixel_mode; | |
/* take care of bitmap flow */ | |
@@ -90,7 +94,7 @@ | |
origin += pitch * (FT_Int)( height - 1 ); | |
/* horizontal in-place FIR filter */ | |
- if ( mode == FT_PIXEL_MODE_LCD && width >= 2 ) | |
+ if ( mode == FT_RENDER_MODE_LCD && width >= 2 ) | |
{ | |
FT_Byte* line = origin; | |
@@ -133,7 +137,7 @@ | |
} | |
/* vertical in-place FIR filter */ | |
- else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 ) | |
+ else if ( mode == FT_RENDER_MODE_LCD_V && height >= 2 ) | |
{ | |
FT_Byte* column = origin; | |
@@ -182,13 +186,13 @@ | |
/* intra-pixel filter used by the legacy filter */ | |
static void | |
_ft_lcd_filter_legacy( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
FT_Byte* weights ) | |
{ | |
FT_UInt width = (FT_UInt)bitmap->width; | |
FT_UInt height = (FT_UInt)bitmap->rows; | |
FT_Int pitch = bitmap->pitch; | |
FT_Byte* origin = bitmap->buffer; | |
- FT_Byte mode = bitmap->pixel_mode; | |
static const unsigned int filters[3][3] = | |
{ | |
@@ -205,7 +209,7 @@ | |
origin += pitch * (FT_Int)( height - 1 ); | |
/* horizontal in-place intra-pixel filter */ | |
- if ( mode == FT_PIXEL_MODE_LCD && width >= 3 ) | |
+ if ( mode == FT_RENDER_MODE_LCD && width >= 3 ) | |
{ | |
FT_Byte* line = origin; | |
@@ -242,7 +246,7 @@ | |
} | |
} | |
} | |
- else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 ) | |
+ else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 ) | |
{ | |
FT_Byte* column = origin; | |
@@ -298,6 +302,7 @@ | |
ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS ); | |
library->lcd_filter_func = ft_lcd_filter_fir; | |
+ library->lcd_extra = 2; | |
return FT_Err_Ok; | |
} | |
@@ -309,11 +314,37 @@ | |
FT_Library_SetLcdFilter( FT_Library library, | |
FT_LcdFilter filter ) | |
{ | |
- static const FT_LcdFiveTapFilter default_weights = | |
- { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; | |
static const FT_LcdFiveTapFilter light_weights = | |
{ 0x00, 0x55, 0x56, 0x55, 0x00 }; | |
+#ifndef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ static const FT_LcdFiveTapFilter default_weights = | |
+ { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; | |
+#else | |
+ FT_LcdFiveTapFilter default_weights; | |
+ if( ftinf && ftinf->filter_params[0] ) | |
+ { | |
+ const int *f=ftinf->filter_params; | |
+ /* Assume we were given integers [0-100] get them to [0-255] */ | |
+ int val; /* 2611=2.55*1024 */ | |
+ val=(f[1]*2611+512)>>10; if( val > 255 ) val=255; | |
+ default_weights[0] = (FT_Byte) val; | |
+ val=(f[2]*2611+512)>>10; if( val > 255 ) val=255; | |
+ default_weights[1] = (FT_Byte) val; | |
+ val=(f[3]*2611+512)>>10; if( val > 255 ) val=255; | |
+ default_weights[2] = (FT_Byte) val; | |
+ val=(f[4]*2611+512)>>10; if( val > 255 ) val=255; | |
+ default_weights[3] = (FT_Byte) val; | |
+ val=(f[5]*2611+512)>>10; if( val > 255 ) val=255; | |
+ default_weights[4] = (FT_Byte) val; | |
+ } else { | |
+ default_weights[0]=0x08; | |
+ default_weights[1]=0x4d; | |
+ default_weights[2]=0x56; | |
+ default_weights[3]=0x4d; | |
+ default_weights[4]=0x08; | |
+ } | |
+#endif | |
if ( !library ) | |
return FT_THROW( Invalid_Library_Handle ); | |
@@ -322,6 +353,7 @@ | |
{ | |
case FT_LCD_FILTER_NONE: | |
library->lcd_filter_func = NULL; | |
+ library->lcd_extra = 0; | |
break; | |
case FT_LCD_FILTER_DEFAULT: | |
@@ -329,6 +361,7 @@ | |
default_weights, | |
FT_LCD_FILTER_FIVE_TAPS ); | |
library->lcd_filter_func = ft_lcd_filter_fir; | |
+ library->lcd_extra = 2; | |
break; | |
case FT_LCD_FILTER_LIGHT: | |
@@ -336,6 +369,7 @@ | |
light_weights, | |
FT_LCD_FILTER_FIVE_TAPS ); | |
library->lcd_filter_func = ft_lcd_filter_fir; | |
+ library->lcd_extra = 2; | |
break; | |
#ifdef USE_LEGACY | |
@@ -343,6 +377,7 @@ | |
case FT_LCD_FILTER_LEGACY: | |
case FT_LCD_FILTER_LEGACY1: | |
library->lcd_filter_func = _ft_lcd_filter_legacy; | |
+ library->lcd_extra = 0; | |
break; | |
#endif | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftobjs.c a/src/base/ftobjs.c | |
--- b/src/base/ftobjs.c 2021-07-15 13:09:04.000000000 +0300 | |
+++ a/src/base/ftobjs.c 2021-09-16 09:15:05.053379751 +0300 | |
@@ -45,7 +45,9 @@ | |
#ifdef FT_CONFIG_OPTION_MAC_FONTS | |
#include "ftbase.h" | |
#endif | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "ftinf.h" | |
+#endif | |
#ifdef FT_DEBUG_LEVEL_TRACE | |
@@ -99,6 +101,11 @@ | |
#define GRID_FIT_METRICS | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include <strings.h> | |
+#include <stdlib.h> | |
+#include "../autofit/aflatin.h" | |
+#endif | |
/* forward declaration */ | |
static FT_Error | |
@@ -777,6 +784,25 @@ | |
ft_lookup_glyph_renderer( FT_GlyphSlot slot ); | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ static void | |
+ ft_glyphslot_enlarge_metrics( FT_GlyphSlot slot, | |
+ FT_Render_Mode mode ) | |
+ { | |
+ FT_Glyph_Metrics* metrics = &slot->metrics; | |
+ FT_Pos enlarge_cbox = 0; | |
+ | |
+ | |
+ /* enlarge for grayscale rendering */ | |
+ if ( mode == FT_RENDER_MODE_NORMAL ) | |
+ enlarge_cbox = 64; | |
+ | |
+ metrics->horiBearingX -= enlarge_cbox; | |
+ metrics->width += 2 * enlarge_cbox; | |
+ } | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
+ | |
+ | |
#ifdef GRID_FIT_METRICS | |
static void | |
ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, | |
@@ -843,8 +869,18 @@ | |
FT_Bool autohint = FALSE; | |
FT_Module hinter; | |
TT_Face ttface = (TT_Face)face; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Bool use_various_tweaks = FALSE; | |
+ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; | |
+ /* Force autohint if no tt instructions */ | |
+ /* NOTE: NEEDS TO BE RUN LATER IN CODE???? */ | |
+ /*if ( use_various_tweaks && | |
+ ttface->num_locations && | |
+ ttface->max_profile.maxSizeOfInstructions == 0 ) | |
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;*/ | |
+#endif | |
if ( !face || !face->size || !face->glyph ) | |
return FT_THROW( Invalid_Face_Handle ); | |
@@ -946,6 +982,18 @@ | |
{ | |
FT_AutoHinter_Interface hinting; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( use_various_tweaks ) | |
+ { | |
+ /* Force slight hinting over full hinting always */ | |
+ load_flags &= ~FT_LOAD_TARGET_LCD; | |
+ load_flags &= ~FT_LOAD_TARGET_LCD_V; | |
+ load_flags &= ~FT_LOAD_TARGET_MONO; | |
+ load_flags &= ~FT_LOAD_TARGET_NORMAL; | |
+ load_flags |= FT_LOAD_TARGET_LIGHT; | |
+ /*printf("%d ", load_flags);*/ | |
+ } | |
+#endif | |
/* try to load embedded bitmaps first if available */ | |
/* */ | |
@@ -991,6 +1039,18 @@ | |
if ( error ) | |
goto Exit; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ infinality_cur_width = 0; | |
+ | |
+ { | |
+ /* fix for sdl_ttf */ | |
+ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); | |
+ | |
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
+ ft_glyphslot_enlarge_metrics( slot, mode ); | |
+ } | |
+#endif | |
+ | |
if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
{ | |
/* check that the loaded outline is correct */ | |
@@ -5353,6 +5413,11 @@ | |
/* That's ok now */ | |
*alibrary = library; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* get Infinality settings */ | |
+ ftinf_env(); | |
+#endif | |
+ | |
return FT_Err_Ok; | |
} | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftoutln.c a/src/base/ftoutln.c | |
--- b/src/base/ftoutln.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/base/ftoutln.c 2021-09-16 09:15:05.053379751 +0300 | |
@@ -22,6 +22,9 @@ | |
#include <freetype/internal/ftdebug.h> | |
#include <freetype/fttrigon.h> | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "ftinf.h" | |
+#endif | |
/************************************************************************** | |
* | |
@@ -907,8 +910,14 @@ | |
{ | |
FT_Vector* points; | |
FT_Int c, first, last; | |
- FT_Orientation orientation; | |
- | |
+ FT_Int orientation; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Bool use_various_tweaks = FALSE; | |
+ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; | |
+ | |
+ if ( use_various_tweaks ) | |
+ ystrength = FT_PIX_FLOOR ( ystrength ); | |
+#endif | |
if ( !outline ) | |
return FT_THROW( Invalid_Outline ); | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftsynth.c a/src/base/ftsynth.c | |
--- b/src/base/ftsynth.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/base/ftsynth.c 2021-09-16 09:15:05.053379751 +0300 | |
@@ -22,6 +22,9 @@ | |
#include <freetype/ftoutln.h> | |
#include <freetype/ftbitmap.h> | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "ftinf.h" | |
+#endif | |
/************************************************************************** | |
* | |
@@ -92,7 +95,10 @@ | |
FT_Face face; | |
FT_Error error; | |
FT_Pos xstr, ystr; | |
- | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Bool use_various_tweaks = FALSE; | |
+ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; | |
+#endif | |
if ( !slot ) | |
return; | |
@@ -110,8 +116,16 @@ | |
ystr = xstr; | |
if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
+ { | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( use_various_tweaks ) | |
+ (void)FT_Outline_EmboldenXY( &slot->outline, | |
+ xstr, | |
+ FT_PIX_FLOOR( ystr ) ); | |
+ else | |
+#endif | |
FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); | |
- | |
+ } | |
else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ | |
{ | |
/* round to full pixels */ | |
@@ -149,6 +163,9 @@ | |
slot->metrics.width += xstr; | |
slot->metrics.height += ystr; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( !use_various_tweaks ) | |
+#endif | |
slot->metrics.horiAdvance += xstr; | |
slot->metrics.vertAdvance += ystr; | |
slot->metrics.horiBearingY += ystr; | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/rules.mk a/src/base/rules.mk | |
--- b/src/base/rules.mk 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/base/rules.mk 2021-09-16 09:15:05.053379751 +0300 | |
@@ -44,6 +44,7 @@ | |
$(BASE_DIR)/ftfntfmt.c \ | |
$(BASE_DIR)/ftgloadr.c \ | |
$(BASE_DIR)/fthash.c \ | |
+ $(BASE_DIR)/ftinf.c \ | |
$(BASE_DIR)/ftlcdfil.c \ | |
$(BASE_DIR)/ftobjs.c \ | |
$(BASE_DIR)/ftoutln.c \ | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/cff/cffobjs.c a/src/cff/cffobjs.c | |
--- b/src/cff/cffobjs.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/cff/cffobjs.c 2021-09-16 09:15:05.053379751 +0300 | |
@@ -42,6 +42,9 @@ | |
#include <freetype/internal/psaux.h> | |
#include <freetype/internal/services/svcfftl.h> | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include "../base/ftinf.h" | |
+#endif | |
/************************************************************************** | |
* | |
@@ -1177,6 +1180,9 @@ | |
driver->hinting_engine = FT_HINTING_ADOBE; | |
driver->no_stem_darkening = TRUE; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if(ftinf) driver->no_stem_darkening = !ftinf->stem_darkening_cff; | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; | |
driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; | |
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/smooth/ftsmooth.c a/src/smooth/ftsmooth.c | |
--- b/src/smooth/ftsmooth.c 2021-02-13 10:16:54.000000000 +0200 | |
+++ a/src/smooth/ftsmooth.c 2021-09-16 09:19:36.749340217 +0300 | |
@@ -24,6 +24,28 @@ | |
#include "ftsmerrs.h" | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+#include <math.h> | |
+#include FT_BITMAP_H | |
+#include <string.h> | |
+#include <strings.h> | |
+#include FT_OUTLINE_H | |
+#include "../base/ftinf.h" | |
+ | |
+#define verbose FALSE | |
+#define STVALUES if (verbose) \ | |
+ printf ( "scale:%f translate:%ld ", *scale_value, *translate_value ); | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
+ | |
+ /* initialize renderer -- init its raster */ | |
+ static FT_Error | |
+ ft_smooth_init( FT_Renderer render ) | |
+ { | |
+ render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); | |
+ | |
+ return 0; | |
+ } | |
+ | |
/* sets render-specific mode */ | |
static FT_Error | |
@@ -76,367 +98,2440 @@ | |
FT_Outline_Get_CBox( &slot->outline, cbox ); | |
} | |
- typedef struct TOrigin_ | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ static FT_Fixed FT_FixedFromFloat(float f) | |
{ | |
- unsigned char* origin; /* pixmap origin at the bottom-left */ | |
- int pitch; /* pitch to go down one row */ | |
+ short value = f; | |
+ unsigned short fract = (f - value) * 0xFFFF; | |
- } TOrigin; | |
-#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ return (FT_Fixed)((long)value << 16 | (unsigned long)fract ); | |
+ } | |
- /* initialize renderer -- init its raster */ | |
- static FT_Error | |
- ft_smooth_init( FT_Renderer render ) | |
+ | |
+ /* ChromeOS sharpening algorithm */ | |
+ /* soften the sub-pixel anti-aliasing and sharpen */ | |
+ static void | |
+ _ft_lcd_chromeos_sharpen( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_Byte cutoff, | |
+ double gamma_value ) | |
+ { | |
+ static FT_Bool initialized_gamma = FALSE; | |
+ static unsigned short gamma_ramp[256]; | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ int ii; | |
+ | |
+ if ( !initialized_gamma ) | |
+ { | |
+ initialized_gamma = TRUE; | |
+ /* linear to voltage */ | |
+ for ( ii = 0; ii < 256; ii++ ) | |
+ { | |
+ gamma_ramp[ii] = (unsigned char) | |
+ ( pow( (double)ii / 255.0, gamma_value ) * 255.0f ); | |
+ if ( gamma_ramp[ii] < cutoff ) | |
+ gamma_ramp[ii] = 0; | |
+ } | |
+ } | |
+ | |
+ /* horizontal in-place sub-pixel sharpening filter */ | |
+ if ( mode == FT_RENDER_MODE_LCD ) | |
{ | |
- FT_Vector* sub = render->root.library->lcd_geometry; | |
+ FT_Byte* line = bitmap->buffer; | |
- /* set up default subpixel geometry for striped RGB panels. */ | |
- sub[0].x = -21; | |
- sub[0].y = 0; | |
- sub[1].x = 0; | |
- sub[1].y = 0; | |
- sub[2].x = 21; | |
- sub[2].y = 0; | |
+ for ( ; height > 0; height--, line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
- render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); | |
- return 0; | |
+ for ( xx = 0; xx < width; xx++ ) | |
+ line[xx] = gamma_ramp[line[xx]]; | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* simple linear scale to handle various sliding values */ | |
+ float | |
+ sliding_scale ( int min_value, | |
+ int max_value, | |
+ float min_amount, | |
+ float max_amount, | |
+ int cur_value ) | |
+ { | |
+ | |
+ float m = ( min_amount - max_amount ) / (float)( min_value - max_value ); | |
+ float result = ( ( (float)cur_value * m) + ( max_amount - max_value * m ) ) ; | |
+ | |
+ if ( min_amount < max_amount ) | |
+ { | |
+ if ( result < min_amount ) | |
+ return min_amount; | |
+ if ( result > max_amount ) | |
+ return max_amount; | |
+ } | |
+ else | |
+ { | |
+ if ( result < max_amount ) | |
+ return max_amount; | |
+ if ( result > min_amount ) | |
+ return min_amount; | |
+ } | |
+ | |
+ return result; | |
+ } | |
+ | |
+ | |
+ /* brightness and contrast adjustment on the bitmap */ | |
+ static FT_Bool | |
+ _ft_bitmap_bc ( FT_Bitmap* bitmap, | |
+ float brightness, | |
+ float contrast ) | |
+ { | |
+ | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_UInt xx; | |
+ | |
+ | |
+ if ( brightness == 0 && contrast == 0 ) | |
+ return FALSE; | |
+ | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch ) | |
+ { | |
+ for ( xx = 0; xx < width - 1; xx += 1 ) | |
+ { | |
+ if ( line[xx] > 0) | |
+ { | |
+ float value = (float)( 255 - line[xx] ) / 256.0; | |
+ FT_Int result = 0; | |
+ | |
+ if ( brightness < 0.0 ) | |
+ value = value * ( 1.0 + brightness ); | |
+ else | |
+ value = value + ( ( 1.0 - value ) * brightness ); | |
+ | |
+ value = ( value - 0.5 ) * | |
+ ( tan ( ( contrast + 1.0 ) * 3.141592/4.0 ) ) + 0.5; | |
+ | |
+ result = (FT_Int)( 255.0 - value * 256.0 ); | |
+ | |
+ if ( result < 0 ) | |
+ result = 0; | |
+ if ( result > 255 ) | |
+ result = 255; | |
+ | |
+ line[xx] = result; | |
+ } | |
+ } | |
+ } | |
+ return TRUE; | |
} | |
- /* This function writes every third byte in direct rendering mode */ | |
+ /* Filter to mimic Windows-style sharpening */ | |
+ /* Determined via 100% experimentation. */ | |
static void | |
- ft_smooth_lcd_spans( int y, | |
- int count, | |
- const FT_Span* spans, | |
- TOrigin* target ) | |
+ _ft_lcd_windows_sharpen( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
+ { | |
+ | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_Bitmap new_bitmap; | |
+ | |
+ | |
+ FT_Bitmap_Init( &new_bitmap ); | |
+ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); | |
+ new_line = (&new_bitmap)->buffer; | |
+ | |
+ if (strength > 0) | |
+ for (height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx, threshold = 128; | |
+ FT_Byte* prevline = line - bitmap->pitch; | |
+ FT_Byte* nextline = line + bitmap->pitch; | |
+ FT_Byte* new_prevline = new_line - bitmap->pitch; | |
+ FT_Byte* new_nextline = new_line + bitmap->pitch; | |
+ | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
{ | |
- unsigned char* dst_line = target->origin - y * target->pitch; | |
- unsigned char* dst; | |
- unsigned short w; | |
+ /* subpixel grid sp11 sp21 sp31 */ | |
+ /* where sp22 is sp12 sp22 sp32 */ | |
+ /* current subpixel. sp13 sp23 sp33 */ | |
+ | |
+ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff, | |
+ prevdiff, nextdiff, sp11, sp21, sp31, sp12, sp22, sp32, | |
+ sp13, sp23, sp33; | |
+ | |
+ sp12 = line [xx-1]; | |
+ sp22 = line [xx]; | |
+ sp32 = line [xx+1]; | |
+ if ( height == bitmap->rows ) | |
+ { | |
+ prevtotal = sp11 = sp21 = sp31 = 0; | |
+ prevdiff = sp22; | |
+ lefttotal = sp12 + sp13; | |
+ righttotal = sp32 + sp33; | |
+ } | |
+ else | |
+ { | |
+ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1]; | |
+ sp11 = prevline [xx-1]; | |
+ sp21 = prevline [xx]; | |
+ sp31 = prevline [xx+1]; | |
+ prevdiff = sp22 - sp21; | |
+ lefttotal = sp11 + sp12 + sp13; | |
+ righttotal = sp31 + sp32 + sp33; | |
+ } | |
- for ( ; count--; spans++ ) | |
- for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) | |
- *dst = spans->coverage; | |
+ if ( height == 1 ) | |
+ { | |
+ nexttotal = sp13 = sp23 = sp33 = 0; | |
+ nextdiff = sp22; | |
+ lefttotal = sp11 + sp12; | |
+ righttotal = sp31 + sp32; | |
+ } | |
+ else | |
+ { | |
+ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1]; | |
+ sp13 = nextline [xx-1]; | |
+ sp23 = nextline [xx]; | |
+ sp33 = nextline [xx+1]; | |
+ nextdiff = sp23 - sp22; | |
+ lefttotal = sp11 + sp12 + sp13; | |
+ righttotal = sp31 + sp32 + sp33; | |
} | |
+ sidesdiff = lefttotal - righttotal; | |
- static FT_Error | |
- ft_smooth_raster_lcd( FT_Renderer render, | |
- FT_Outline* outline, | |
- FT_Bitmap* bitmap ) | |
+ if ( sidesdiff < 0 ) | |
+ sidesdiff *= -1; | |
+ | |
+ if ( prevdiff < 0 ) | |
+ prevdiff *= -1; | |
+ | |
+ if ( nextdiff < 0 ) | |
+ nextdiff *= -1; | |
+ | |
+ /* if the current pixel is less than threshold, and greater than 0 */ | |
+ if ( sp22 <= threshold && sp22 > 0 ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- FT_Vector* sub = render->root.library->lcd_geometry; | |
- FT_Pos x, y; | |
+ /* A pixel is horizontally isolated if: */ | |
+ /* 1: All upper adjecent pixels are >= threshold */ | |
+ if ( prevtotal >= nexttotal && | |
+ abs( sp11 - sp12 ) > 5 && | |
+ abs( sp21 - sp22 ) > 5 && | |
+ abs( sp31 - sp32 ) > 5 && /* not a vert stem end */ | |
+ sp11 >= threshold && | |
+ sp21 >= threshold && | |
+ sp31 >= threshold && | |
+ abs( sp23 - sp22 ) > 15 ) /* not on a vert stem */ | |
+ { | |
+ /* darken upper adjacent subpixel; lighten current */ | |
+ if ( height != (FT_UInt)bitmap->rows ) | |
+ new_prevline[xx] += ( ( 255 - new_prevline[xx] ) | |
+ * strength ) / 100 ; | |
- FT_Raster_Params params; | |
- TOrigin target; | |
+ new_line[xx] -= ( new_line[xx] * strength ) / 100; | |
+ if ( height != 1 && height != (FT_UInt)bitmap->rows ) | |
+ if ( new_nextline[xx] > 155 + ( 100 - strength ) ) | |
+ new_prevline[xx] = 255; | |
- /* Render 3 separate coverage bitmaps, shifting the outline. */ | |
- /* Set up direct rendering to record them on each third byte. */ | |
- params.source = outline; | |
- params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; | |
- params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans; | |
- params.user = ⌖ | |
- | |
- params.clip_box.xMin = 0; | |
- params.clip_box.yMin = 0; | |
- params.clip_box.xMax = bitmap->width; | |
- params.clip_box.yMax = bitmap->rows; | |
- | |
- if ( bitmap->pitch < 0 ) | |
- target.origin = bitmap->buffer; | |
- else | |
- target.origin = bitmap->buffer | |
- + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; | |
- | |
- target.pitch = bitmap->pitch; | |
- | |
- FT_Outline_Translate( outline, | |
- -sub[0].x, | |
- -sub[0].y ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[0].x; | |
- y = sub[0].y; | |
- if ( error ) | |
- goto Exit; | |
+ } | |
+ else if ( nexttotal > prevtotal && | |
+ abs( sp13 - sp12 ) > 5 && | |
+ abs( sp23 - sp22 ) > 5 && | |
+ abs( sp33 - sp32 ) > 5 && | |
+ /* 2: All lower adjecent pixels are >= threshold */ | |
+ sp13 >= threshold && | |
+ sp23 >= threshold && | |
+ sp33 >= threshold && | |
+ abs( sp22 - sp21 ) > 15 ) | |
+ { | |
+ /* darken lower adjacent subpixel; lighten current */ | |
+ if ( height != 1 ) | |
+ new_nextline[xx] += ( 255 - new_nextline[xx] ) * strength / 100; | |
- target.origin++; | |
- FT_Outline_Translate( outline, | |
- sub[0].x - sub[1].x, | |
- sub[0].y - sub[1].y ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[1].x; | |
- y = sub[1].y; | |
- if ( error ) | |
- goto Exit; | |
+ new_line[xx] -= ( new_line[xx] * strength ) / 100; | |
- target.origin++; | |
- FT_Outline_Translate( outline, | |
- sub[1].x - sub[2].x, | |
- sub[1].y - sub[2].y ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[2].x; | |
- y = sub[2].y; | |
+ if ( height != 1 ) | |
+ if ( new_nextline[xx] > 155 + ( 100 - strength ) ) | |
+ new_nextline[xx] = 255; | |
- Exit: | |
- FT_Outline_Translate( outline, x, y ); | |
+ } | |
+ } | |
+ else if ( sp22 > threshold && sp22 < 255 ) | |
+ { | |
+ if ( sp11 <= threshold && | |
+ abs( sp13 - sp12 ) > 5 && | |
+ abs( sp23 - sp22 ) > 5 && | |
+ abs( sp33 - sp32 ) > 5 && | |
+ sp21 <= threshold && | |
+ sp31 <= threshold && | |
+ prevtotal <= nexttotal && | |
+ abs( sp22 - sp21 ) > 15 ) | |
+ { | |
+ /* bring this subpixel 1/3 of the way to 255 at 100% strength */ | |
+ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; | |
- return error; | |
+ if ( height != (FT_UInt)bitmap->rows ) | |
+ new_prevline[xx] -= ( new_prevline[xx] * strength ) / 300; | |
} | |
+ else if ( sp13 <= threshold && | |
+ abs( sp11 - sp12 ) > 5 && | |
+ abs( sp21 - sp22 ) > 5 && | |
+ abs( sp31 - sp32 ) > 5 && | |
+ sp23 <= threshold && | |
+ sp33 <= threshold && | |
+ nexttotal < prevtotal && | |
+ abs( sp23 - sp22 ) > 15 ) | |
+ { | |
+ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; | |
+ if ( height != 1 ) | |
+ new_nextline[xx] -= ( new_nextline[xx] * strength ) / 300; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
+ } | |
- static FT_Error | |
- ft_smooth_raster_lcdv( FT_Renderer render, | |
- FT_Outline* outline, | |
- FT_Bitmap* bitmap ) | |
+ | |
+ static void | |
+ _ft_lcd_darken_x ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- int pitch = bitmap->pitch; | |
- FT_Vector* sub = render->root.library->lcd_geometry; | |
- FT_Pos x, y; | |
- FT_Raster_Params params; | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_Bitmap new_bitmap; | |
+ int factor1, factor2; | |
+ int bias = 0; | |
+ FT_Bitmap_Init( &new_bitmap ); | |
- params.target = bitmap; | |
- params.source = outline; | |
- params.flags = FT_RASTER_FLAG_AA; | |
+ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); | |
+ new_line = (&new_bitmap)->buffer; | |
- /* Render 3 separate coverage bitmaps, shifting the outline. */ | |
- /* Notice that the subpixel geometry vectors are rotated. */ | |
- /* Triple the pitch to render on each third row. */ | |
- bitmap->pitch *= 3; | |
- bitmap->rows /= 3; | |
- | |
- FT_Outline_Translate( outline, | |
- -sub[0].y, | |
- sub[0].x ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[0].y; | |
- y = -sub[0].x; | |
- if ( error ) | |
- goto Exit; | |
+ if ( strength > 0 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
+ FT_Byte* prevline = line - bitmap->pitch; | |
+ FT_Byte* nextline = line + bitmap->pitch; | |
- bitmap->buffer += pitch; | |
- FT_Outline_Translate( outline, | |
- sub[0].y - sub[1].y, | |
- sub[1].x - sub[0].x ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[1].y; | |
- y = -sub[1].x; | |
- bitmap->buffer -= pitch; | |
- if ( error ) | |
- goto Exit; | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ /* subpixel grid sp11 sp21 sp31 */ | |
+ /* where sp22 is sp12 sp22 sp32 */ | |
+ /* current subpixel. sp13 sp23 sp33 */ | |
- bitmap->buffer += 2 * pitch; | |
- FT_Outline_Translate( outline, | |
- sub[1].y - sub[2].y, | |
- sub[2].x - sub[1].x ); | |
- error = render->raster_render( render->raster, ¶ms ); | |
- x = sub[2].y; | |
- y = -sub[2].x; | |
- bitmap->buffer -= 2 * pitch; | |
+ FT_Int sp21, sp12, sp22, sp32, sp23; | |
- Exit: | |
- FT_Outline_Translate( outline, x, y ); | |
+ sp12 = line [xx-1]; | |
+ sp22 = line [xx]; | |
+ sp32 = line [xx+1]; | |
- bitmap->pitch /= 3; | |
- bitmap->rows *= 3; | |
+ if ( height == bitmap->rows ) | |
+ sp21 = 0; | |
+ else | |
+ sp21 = prevline [xx]; | |
+ | |
+ if ( height == 1 ) | |
+ sp23 = 0; | |
+ else | |
+ sp23 = nextline [xx]; | |
+ | |
+ /* darken subpixel if neighbor above and below are much less than */ | |
+ /* safer but less effective */ | |
+ factor1 = 5; | |
+ factor2 = 5; | |
+ | |
+ /* make matches in the middle of glyph slightly darker */ | |
+ /*if (height > 1 && height < (FT_UInt)bitmap->rows) bias = 1;*/ | |
+ | |
+ if ( sp22 > factor1 * sp21 && | |
+ sp22 > factor1 * sp23 && | |
+ sp22 > factor2 && | |
+ sp12 > 16 && | |
+ sp32 > 16 ) | |
+ if ( new_line[xx] < ( strength * 255 ) / 100 ) | |
+ new_line[xx] = (strength * 255 ) / 100 | |
+ + bias * ( 255 - ( strength * 255 ) / 100 ) / 3; | |
- return error; | |
+ } | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
} | |
-#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
- /* initialize renderer -- init its raster */ | |
- static FT_Error | |
- ft_smooth_init( FT_Renderer render ) | |
+ static void | |
+ _ft_lcd_darken_y ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
{ | |
- /* set up default LCD filtering */ | |
- FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); | |
- render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_Bitmap new_bitmap; | |
- return 0; | |
+ | |
+ FT_Bitmap_Init( &new_bitmap ); | |
+ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); | |
+ new_line = (&new_bitmap)->buffer; | |
+ | |
+ if ( strength > 0 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
+ | |
+ | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ if ( line[xx] > line[xx-1] && line[xx] > line[xx+1] ) | |
+ { | |
+ if (new_line[xx] > 0) | |
+ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; | |
+ new_line[xx-1] += ( strength * ( 255 - line[xx-1] ) ) / 100; | |
+ new_line[xx+1] += ( strength * ( 255 - line[xx+1] ) ) / 100; | |
+ } | |
+ } | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
} | |
- static FT_Error | |
- ft_smooth_raster_lcd( FT_Renderer render, | |
- FT_Outline* outline, | |
- FT_Bitmap* bitmap ) | |
+ static void | |
+ _ft_bitmap_cap ( FT_Bitmap* bitmap, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- FT_Vector* points = outline->points; | |
- FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); | |
- FT_Vector* vec; | |
- FT_Raster_Params params; | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_UInt cur_value = 0; | |
+ FT_Bitmap new_bitmap; | |
- params.target = bitmap; | |
- params.source = outline; | |
- params.flags = FT_RASTER_FLAG_AA; | |
+ FT_Bitmap_Init( &new_bitmap ); | |
+ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); | |
+ new_line = (&new_bitmap)->buffer; | |
- /* implode outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
- vec->x *= 3; | |
+ if ( strength > 0 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
- /* render outline into the bitmap */ | |
- error = render->raster_render( render->raster, ¶ms ); | |
- /* deflate outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
- vec->x /= 3; | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ cur_value = ( new_line[xx-1] + new_line[xx] + new_line[xx+1] ) / 3; | |
+ if ( cur_value > ( strength * 255 ) / 100 ) | |
+ { | |
+ FT_UInt new_factor = ( strength * 255 ) / 100; | |
+ new_line[xx] = ( new_line[xx] * new_factor ) / cur_value; | |
+ new_line[xx+1] = ( new_line[xx+1] * new_factor ) / cur_value; | |
+ new_line[xx-1] = ( new_line[xx-1] * new_factor ) / cur_value; | |
+ } | |
+ } | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
+ } | |
- return error; | |
+ static int | |
+ pseudo_gamma ( int val, float value ) | |
+ { | |
+ return 256 * ( 1.0f - powf( ( 1.0f - val * (1.0f/256.0f) ), 1.0f / value ) ); | |
} | |
+#if(0) | |
+ static void | |
+ _ft_bitmap_embolden ( FT_Bitmap* bitmap, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
+ { | |
- static FT_Error | |
- ft_smooth_raster_lcdv( FT_Renderer render, | |
- FT_Outline* outline, | |
- FT_Bitmap* bitmap ) | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_Bitmap new_bitmap; | |
+ FT_UInt xx; | |
+ | |
+ | |
+ FT_Bitmap_Init(&new_bitmap); | |
+ FT_Bitmap_Copy(library, bitmap, &new_bitmap); | |
+ new_line = (&new_bitmap)->buffer; | |
+ | |
+ if ( strength > 0 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- FT_Vector* points = outline->points; | |
- FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); | |
- FT_Vector* vec; | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ FT_Int new_value = 0; | |
- FT_Raster_Params params; | |
+ new_value = ( strength * line [xx-1] ) / 100 | |
+ + pseudo_gamma( line [xx], .75 ) | |
+ + (strength * line [xx+1] ) / 100; | |
+ if ( new_value > 255 ) | |
+ new_value = 255; | |
- params.target = bitmap; | |
- params.source = outline; | |
- params.flags = FT_RASTER_FLAG_AA; | |
+ new_line[xx] = new_value; | |
+ } | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
+ } | |
- /* implode outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
- vec->y *= 3; | |
- /* render outline into the bitmap */ | |
- error = render->raster_render( render->raster, ¶ms ); | |
- /* deflate outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
- vec->y /= 3; | |
+ static void | |
+ _ft_bitmap_gamma ( FT_Bitmap* bitmap, | |
+ float strength ) | |
+ { | |
- return error; | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_UInt xx; | |
+ | |
+ | |
+ if ( strength > 0 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch ) | |
+ { | |
+ | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ if ( abs( line[xx-1] - line[xx] ) < 20 || | |
+ abs( line[xx+1] - line[xx] ) < 20 ) | |
+ line [xx] = pseudo_gamma( line [xx], strength ) ; | |
+ } | |
+ } | |
+ } | |
+#endif | |
+ | |
+ /* Fringe filter */ | |
+ static void | |
+ _ft_lcd_fringe_filter ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
+ { | |
+ | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* new_line; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_Bitmap new_bitmap; | |
+ | |
+ | |
+ FT_Bitmap_Init(&new_bitmap); | |
+ | |
+ line = bitmap->buffer; | |
+ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); | |
+ new_line = (&new_bitmap)->buffer; | |
+ | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch, new_line += bitmap->pitch ) | |
+ { | |
+ /* Threshold set to 1/2 pixel intensity */ | |
+ FT_UInt xx, threshold = 128; | |
+ | |
+ /* Hack to make this work when bitmap is at first or last line */ | |
+ FT_Int fudge = bitmap->pitch * (height == (FT_UInt)bitmap->rows); | |
+ | |
+ FT_Byte* prevline = line - bitmap->pitch + fudge; | |
+ FT_Byte* nextline = line + bitmap->pitch; | |
+ | |
+ | |
+ for ( xx = 1; xx < width - 1; xx += 1 ) | |
+ { | |
+ /* subpixel grid sp11 sp21 sp31 */ | |
+ /* where sp22 is sp12 sp22 sp32 */ | |
+ /* current subpixel. sp13 sp23 sp33 */ | |
+ | |
+ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff, | |
+ leftdiff, rightdiff, prevdiff, nextdiff, sp11, sp21, sp31, | |
+ sp12, sp22, sp32, sp13, sp23, sp33; | |
+ | |
+ sp12 = line [xx-1]; | |
+ sp22 = line [xx]; | |
+ sp32 = line [xx+1]; | |
+ | |
+ /* if at max height fake out some values */ | |
+ if ( height == (FT_UInt)bitmap->rows ) | |
+ { | |
+ prevtotal = sp11 = sp21 = sp31 = 0; | |
+ prevdiff = sp22; | |
+ lefttotal = sp12 + sp13; | |
+ righttotal = sp32 + sp33; | |
+ } | |
+ else | |
+ { | |
+ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1]; | |
+ sp11 = prevline [xx-1]; | |
+ sp21 = prevline [xx]; | |
+ sp31 = prevline [xx+1]; | |
+ prevdiff = sp22 - sp21; | |
+ lefttotal = sp11 + sp12 + sp13; | |
+ righttotal = sp31 + sp32 + sp33; | |
+ } | |
+ | |
+ /* if at min height fake out some values */ | |
+ if ( height == 1 ) | |
+ { | |
+ nexttotal = sp13 = sp23 = sp33 = 0; | |
+ nextdiff = sp22; | |
+ lefttotal = sp11 + sp12; | |
+ righttotal = sp31 + sp32; | |
+ } | |
+ else | |
+ { | |
+ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1]; | |
+ sp13 = nextline [xx-1]; | |
+ sp23 = nextline [xx]; | |
+ sp33 = nextline [xx+1]; | |
+ nextdiff = sp23 - sp22; | |
+ lefttotal = sp11 + sp12 + sp13; | |
+ righttotal = sp31 + sp32 + sp33; | |
+ } | |
+ | |
+ sidesdiff = lefttotal - righttotal; | |
+ leftdiff = sp22 - sp12; | |
+ rightdiff = sp32 - sp22; | |
+ | |
+ if ( sidesdiff < 0 ) | |
+ sidesdiff *= -1; | |
+ | |
+ if ( prevdiff < 0 ) | |
+ prevdiff *= -1; | |
+ | |
+ if ( nextdiff < 0 ) | |
+ nextdiff *= -1; | |
+ | |
+ if ( leftdiff < 0 ) | |
+ leftdiff *= -1; | |
+ | |
+ if ( rightdiff < 0 ) | |
+ rightdiff *= -1; | |
+ | |
+ /* if the current subpixel is less than threshold, and varies only | |
+ slightly to left or right, lighten it */ | |
+ if ( sp22 <= threshold && sp22 > 0 && | |
+ ( leftdiff < 10 || rightdiff < 10 ) ) | |
+ { | |
+ /* A pixel is horizontally isolated if: */ | |
+ /* 1: All upper adjecent subpixels are >= threshold and all lower | |
+ adjacent ones are essentially white */ | |
+ if ( prevtotal >= nexttotal && | |
+ sp11 >= threshold && | |
+ sp21 >= threshold && | |
+ sp31 >= threshold && | |
+ sp13 < 2 && | |
+ sp23 < 2 && | |
+ sp33 < 2 ) | |
+ | |
+ { | |
+ new_line[xx] -= ( new_line[xx] * strength ) / 100; | |
+ | |
+ if ( leftdiff < 10 ) | |
+ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */ | |
+ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200; | |
+ | |
+ if ( rightdiff < 10 ) | |
+ /* OPPORTUNITY FOR IMPROVEMENT */ | |
+ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200; | |
+ } | |
+ else if ( nexttotal > prevtotal && | |
+ /* 2: the inverse of above */ | |
+ sp13 >= threshold && | |
+ sp23 >= threshold && | |
+ sp33 >= threshold && | |
+ sp11 < 2 && | |
+ sp21 < 2 && | |
+ sp31 < 2 ) | |
+ { | |
+ new_line[xx] -= ( new_line[xx] * strength ) / 100; | |
+ | |
+ if ( leftdiff < 10 ) | |
+ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */ | |
+ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200; | |
+ | |
+ if ( rightdiff < 10 ) | |
+ /* OPPORTUNITY FOR IMPROVEMENT */ | |
+ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200; | |
+ } | |
+ } | |
+ /* otherwise if the current subpixel is more than threshold, and varies | |
+ slightly to left or right, darken it */ | |
+ else if ( sp22 > threshold && | |
+ sp22 < 255 && | |
+ ( leftdiff < 10 || | |
+ rightdiff < 10 ) ) | |
+ { | |
+ if ( sp11 <= 2 && | |
+ sp21 <= 2 && | |
+ sp31 <= 2 && | |
+ sp13 >= threshold && | |
+ sp23 >= threshold && | |
+ sp33 >= threshold && | |
+ prevtotal < nexttotal ) | |
+ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100; | |
+ | |
+ else if ( sp13 <= 2 && | |
+ sp23 <= 2 && | |
+ sp33 <= 2 && | |
+ nexttotal < prevtotal && | |
+ sp11 >= threshold && | |
+ sp21 >= threshold && | |
+ sp31 >= threshold ) | |
+ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100; | |
+ | |
+ } | |
} | |
+ } | |
+ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); | |
+ FT_Bitmap_Done( library, &new_bitmap ); | |
+ } | |
+ | |
+ | |
+ /* Grayscale filter */ | |
+ static void | |
+ _ft_lcd_grayscale_filter ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_UInt strength, | |
+ FT_Library library ) | |
+ { | |
+ | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* line = bitmap->buffer; | |
+ | |
+ | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
-#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
-/* Oversampling scale to be used in rendering overlaps */ | |
-#define SCALE ( 1 << 2 ) | |
+ for ( xx = 0; xx < width - 1; xx += 3 ) | |
+ { | |
+ FT_UInt total = line [xx] + line [xx + 1] + line [xx + 2]; | |
+ line[xx] = ( ( 100 - strength ) * line[xx] | |
+ + strength * ( total / 3 ) ) / 100; | |
+ line[xx+1] = ( ( 100 - strength ) * line[xx+1] | |
+ + strength * ( total / 3 ) ) / 100; | |
+ line[xx+2] = ( ( 100 - strength ) * line[xx+2] | |
+ + strength * ( total / 3 ) ) / 100; | |
+ } | |
+ } | |
+ } | |
+ | |
+/* | |
+ These need to be in sync with params inside ftinf.c | |
+ (not ideal but perhaps better than making these public) | |
+ */ | |
+#define STEM_WIDTH_2_PPEM 18 | |
+#define MAX_PPEM 100 | |
+ | |
+ typedef struct Stem_Segment_ | |
+ { | |
+ FT_Long x1; | |
+ FT_Long x2; | |
+ FT_Int y; | |
+ } Stem_Segment; | |
+ | |
+ typedef struct Stem_Center_ | |
+ { | |
+ FT_Long x; | |
+ FT_Long y; | |
+ FT_Long w; | |
+ FT_Long x1; | |
+ FT_Long x2; | |
+ } Stem_Center; | |
+ | |
+ typedef struct Stem_ | |
+ { | |
+ FT_Long center; | |
+ FT_Long count; | |
+ FT_Long rcount; /* used to count within a range in possible stems */ | |
+ FT_Long width; | |
+ FT_Long height; | |
+ FT_Short zone; /* 1 2 or 3 */ | |
+ FT_Bool generated; | |
+ } Stem; | |
- /* This function averages inflated spans in direct rendering mode */ | |
static void | |
- ft_smooth_overlap_spans( int y, | |
- int count, | |
- const FT_Span* spans, | |
- TOrigin* target ) | |
+ swap_stem ( Stem* s1, Stem* s2 ) | |
{ | |
- unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; | |
- unsigned short x; | |
- unsigned int cover, sum; | |
+ Stem s; | |
+ s.center = s1->center; | |
+ s.count = s1->count; | |
+ s.rcount = s1->rcount; | |
+ s.width = s1->width; | |
+ s.zone = s1->zone; | |
+ s.generated = s1->generated; | |
+ | |
+ s1->center = s2->center; | |
+ s1->count = s2->count; | |
+ s1->rcount = s2->rcount; | |
+ s1->width = s2->width; | |
+ s1->zone = s2->zone; | |
+ s1->generated = s2->generated; | |
+ | |
+ s2->center = s.center; | |
+ s2->count = s.count; | |
+ s2->rcount = s.rcount; | |
+ s2->width = s.width; | |
+ s2->zone = s.zone; | |
+ s2->generated = s.generated; | |
+ } | |
+ | |
+ /* Stem alignment for bitmaps; A hack with very nice results */ | |
+ /* Ideally this could be implemented on the outline, prior to | |
+ * rasterization. Possible future enhancement is to use the | |
+ * warper code to achieve this */ | |
+ static void | |
+ _lcd_stem_align ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_GlyphSlot slot, | |
+ FT_Long* translate_value, | |
+ float* scale_value, | |
+ FT_UInt alignment_strength, | |
+ FT_UInt fitting_strength, | |
+ float* embolden_value | |
+ ) | |
+ { | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ | |
+ Stem_Segment* segments; | |
+ Stem_Segment* leftmost_segment; | |
+ Stem_Segment* rightmost_segment; | |
+ Stem_Segment* leftmost_segment_not_extrema; | |
+ Stem_Segment* rightmost_segment_not_extrema; | |
+ Stem* stems; | |
+ Stem* possible_stems; | |
+ Stem* leftmost_stem; | |
+ Stem* rightmost_stem; | |
+ Stem_Data* known_stem_values; | |
+ Stem_Center* centers; | |
+ FT_Long leftmost_point = width * 256; | |
+ FT_Long rightmost_point = 0; | |
+ FT_Long leftmost_point_not_extrema = width * 256; | |
+ FT_Long rightmost_point_not_extrema = 0; | |
+ FT_Long num_segments = 0; | |
+ FT_Long num_centers = 0; | |
+ FT_Long *stem_centers; | |
+ FT_UInt h; | |
+ FT_ULong valid_stems = 0, valid_possible_stems = 0; | |
+ FT_Long center, stem_matches, stem_matches_ledge; | |
+ FT_Long stem_matches_redge, next_center, last_matching_center; | |
+ FT_Long last_matching_ledge, last_matching_redge, this_center; | |
+ FT_Int max_strength; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_UInt current_value = 0; | |
+ FT_UInt xx; | |
+ FT_Long linearHoriAdvance = slot->linearHoriAdvance >> 10; | |
+ | |
+ FT_Int m_horiBearingX = slot->metrics.horiBearingX; | |
+ FT_Int m_horiAdvance = slot->metrics.horiAdvance; | |
+ FT_Int m_width = slot->metrics.width; | |
+ FT_Pos one_pixel = 768; | |
+ FT_Pos one_third_pixel = 256; | |
+ FT_Int columns_per_pixel = 3; | |
+ /*FT_Int extra_columns = 6;*/ | |
+ | |
+ /* on / off flags for testing different features */ | |
+ FT_Bool strategy_translate_using_closest_stem = TRUE; | |
+ FT_Bool strategy_scale_to_closest_centers = FALSE; | |
+ FT_Bool strategy_scale_to_closest_centers_up_only = FALSE; | |
+ FT_Bool strategy_always_use_distance_ceiling = FALSE; | |
+ FT_Bool strategy_auto_change_center_offset = TRUE; | |
+ FT_Bool strategy_use_m_control = FALSE; | |
+ FT_Bool strategy_correct_out_of_bounds_outlines = FALSE; | |
+ FT_Bool strategy_also_use_edge_detection_for_stems = FALSE; | |
+ FT_Bool strategy_use_strengths = TRUE; | |
+ FT_Bool strategy_synthesize_stems = FALSE; | |
+ FT_Bool strategy_bearing_correction = TRUE; | |
+ FT_Bool strategy_use_d_correction = TRUE; | |
+ FT_Bool strategy_fit_to_width = FALSE; | |
+ /*FT_Bool strategy_center_glyph = FALSE;*/ | |
+ | |
+ const FT_Int MIN_PPEM = 7; | |
+ /*const FT_Int MAX_PPEM = 100;*/ | |
+ const FT_Int MAX_STEMS = 3; | |
+ FT_Int ppem = 0; | |
+ | |
+ Stem_Data stem_data; | |
+ | |
+ /* reset to default */ | |
+ *scale_value = 1.0; | |
+ | |
+ /* Simply return in odd cases where these don't seem to be set */ | |
+ /* Flash and some pdf viewers will crash otherwise */ | |
+ if ( !slot->face || | |
+ !slot->face->size || | |
+ !slot->face->size->metrics.x_ppem ) | |
+ return; | |
+ | |
+ if ( slot->face->size->metrics.x_ppem > MAX_PPEM ) | |
+ return; | |
+ | |
+ if ( slot->face->size->metrics.x_ppem < MIN_PPEM ) | |
+ return; | |
+ | |
+ if ( !FT_IS_SCALABLE( slot->face ) ) | |
+ return; | |
+ | |
+ ppem = slot->face->size->metrics.x_ppem; | |
+ | |
+ if ( ppem < 9 ) | |
+ return; | |
+ if ( ppem > 20 ) | |
+ strategy_use_m_control = TRUE; | |
+ | |
+ /* only perform alignment on styles we know, that aren't bold or italic */ | |
+ /* perhaps detection could be added on those that are not set? */ | |
+ /* Require certain ppems for narrow and light fonts */ | |
+ if( slot->face->style_name ) | |
+ { | |
+ if ( strcasestr( slot->face->style_name, "Italic" ) || | |
+ strcasestr( slot->face->style_name, "Oblique" ) || | |
+ strcasestr( slot->face->style_name, "Script" ) || | |
+ strcasestr( slot->face->style_name, "Handwriting" ) || | |
+ strcasestr( slot->face->style_name, "Bold" ) || | |
+ strcasestr( slot->face->style_name, "Black" ) || | |
+ ( ( strcasestr( slot->face->style_name, "Extra Thin" ) || | |
+ strcasestr( slot->face->style_name, "Extra Light" ) ) && | |
+ ppem < 10 ) || | |
+ ( strcasestr( slot->face->style_name, "Thin" ) | |
+ && ppem < 10 ) || | |
+ ( strcasestr( slot->face->style_name, "Light" ) | |
+ && ppem < 10 ) || | |
+ ( strcasestr( slot->face->style_name, "Narrow" ) | |
+ && ppem < 15 ) || | |
+ ( strcasestr( slot->face->style_name, "Condensed" ) | |
+ && ppem < 20 ) ) | |
+ return; | |
+ } | |
+ | |
+ if( slot->face->family_name ) | |
+ { | |
+ if ( strcasestr( slot->face->family_name, "Italic" ) || | |
+ strcasestr( slot->face->family_name, "Oblique" ) || | |
+ strcasestr( slot->face->family_name, "Script" ) || | |
+ strcasestr( slot->face->family_name, "Handwriting" ) || | |
+ strcasestr( slot->face->family_name, "Bold" ) || | |
+ strcasestr( slot->face->family_name, "Black" ) || | |
+ ( ( strcasestr( slot->face->family_name, "Extra Thin" ) || | |
+ strcasestr( slot->face->family_name, "Extra Light" ) ) && | |
+ ppem < 10 ) || | |
+ ( strcasestr( slot->face->family_name, "Thin" ) | |
+ && ppem < 10 ) || | |
+ ( strcasestr( slot->face->family_name, "Light" ) | |
+ && ppem < 10 ) || | |
+ ( strcasestr( slot->face->family_name, "Narrow" ) | |
+ && ppem < 15 ) || | |
+ ( strcasestr( slot->face->family_name, "Condensed" ) | |
+ && ppem < 20 ) ) | |
+ return; | |
+ } | |
+ else if ( slot->face->style_flags ) | |
+ { | |
+ if ( slot->face->style_flags & FT_STYLE_FLAG_ITALIC || | |
+ slot->face->style_flags & FT_STYLE_FLAG_BOLD || | |
+ FT_IS_TRICKY( slot->face ) ) | |
+ return; | |
+ } | |
+ else return; | |
+ | |
+ if ( mode != FT_RENDER_MODE_LCD ) | |
+ { | |
+ columns_per_pixel = 1; | |
+ one_pixel = 256; | |
+ one_third_pixel = 85; | |
+ /*extra_columns = 0;*/ | |
+ /* until this can be figured out just return */ | |
+ /* There are issues with missing glyphs */ | |
+ return; | |
+ } | |
+ | |
+ known_stem_values=&stem_data; | |
+ if ( ftinf && ftinf->use_known_settings_on_selected_fonts ) | |
+ { | |
+ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, TRUE ); | |
+ /* translate value may be set for < 10 */ | |
+ if (known_stem_values->stem_translating_only > -1024 ) | |
+ { | |
+ *translate_value = known_stem_values->stem_translating_only; | |
+ return; | |
+ } | |
+ if( known_stem_values->bearing_correction == FALSE ) | |
+ strategy_bearing_correction = FALSE; | |
+ } else | |
+ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, FALSE ); | |
+ | |
+ if ( known_stem_values->use_100 || | |
+ known_stem_values->m >= 0 ) | |
+ { | |
+ alignment_strength = fitting_strength = 100; | |
+ strategy_use_m_control = TRUE; | |
+ } | |
+ | |
+ if ( known_stem_values->edge_detection ) | |
+ strategy_also_use_edge_detection_for_stems = TRUE; | |
+ | |
+ /* Allocate */ | |
+ segments = NULL; | |
+ leftmost_segment = (Stem_Segment*) malloc( 4*sizeof ( Stem_Segment ) ); | |
+ leftmost_segment_not_extrema = leftmost_segment+1; | |
+ rightmost_segment = leftmost_segment+2; | |
+ rightmost_segment_not_extrema = leftmost_segment+3; | |
+ | |
+ stems = (Stem*) malloc ( (2*MAX_STEMS+2) * sizeof ( Stem ) ); | |
+ possible_stems = stems+MAX_STEMS; | |
+ leftmost_stem = possible_stems+MAX_STEMS; | |
+ rightmost_stem = leftmost_stem + 1; | |
+ centers = NULL; | |
+ | |
+ if ( verbose ) | |
+ printf("\n"); | |
+ | |
+ /* Initialize */ | |
+ stem_centers=(FT_Long*)calloc( width * 256, sizeof(stem_centers[0]) ); | |
+ | |
+ rightmost_segment->x1 = 0; | |
+ rightmost_segment->x2 = 0; | |
+ rightmost_segment->y = 0; | |
+ leftmost_segment->x1 = 99999999; | |
+ leftmost_segment->x2 = 0; | |
+ leftmost_segment->y = 0; | |
+ | |
+ rightmost_segment_not_extrema->x1 = 0; | |
+ rightmost_segment_not_extrema->x2 = 0; | |
+ rightmost_segment_not_extrema->y = 0; | |
+ leftmost_segment_not_extrema->x1 = 99999999; | |
+ leftmost_segment_not_extrema->x2 = 0; | |
+ leftmost_segment_not_extrema->y = 0; | |
+ | |
+ /* Locate stem centers for later processing */ | |
+ for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch ) | |
+ { | |
+ current_value = 0; | |
+ /* Calculate various sums and stem widths of glyph */ | |
+ for ( xx = 0; xx < width; xx += 1 ) | |
+ { | |
+ /* Reallocate (in blocks of 64) */ | |
+ if( num_segments % 64 == 0 ) | |
+ segments = (Stem_Segment*) realloc | |
+ ( segments, ( num_segments + 64 ) * sizeof ( Stem_Segment ) ); | |
+ | |
+ /* if line is white, and now has color, it's the start of a stem */ | |
+ if ( current_value == 0 && line[xx] > 0 ) | |
+ { | |
+ /* start of stem */ | |
+ segments[num_segments].x1 = 256 * xx + ( 255 - line[xx] ); | |
+ segments[num_segments].y = h; | |
+ } | |
+ | |
+ /* otherwise, if it's currently black and the new value is 0, | |
+ it's the end of a stem */ | |
+ else if ( ( current_value > 0 && line[xx] == 0 ) || | |
+ ( current_value > 0 && xx == width - 1 ) ) | |
+ { | |
+ FT_Long stem_center_x; | |
+ segments[num_segments].x2 = 256 * ( xx - 1 ) + line[xx-1]; | |
+ | |
+ if ( xx == width - 1 ) | |
+ segments[num_segments].x2 += line[xx]; | |
+ | |
+ /*stem center is average of start and end of stem */ | |
+ stem_center_x = ( segments[num_segments].x2 | |
+ + segments[num_segments].x1 ) / 2; | |
+ | |
+ /* Reallocate (in blocks of 32) */ | |
+ if( num_centers % 32 == 0 ) | |
+ centers = (Stem_Center*) realloc | |
+ ( centers, ( num_centers + 32 ) * sizeof ( Stem_Center ) ); | |
+ centers[num_centers].x = stem_center_x; | |
+ centers[num_centers].y = h; | |
+ centers[num_centers].x1 = segments[num_segments].x1; | |
+ centers[num_centers].x2 = segments[num_segments].x2; | |
+ | |
+ num_centers++; | |
+ | |
+ stem_centers[stem_center_x] += 1; | |
+ | |
+ /* Find left and rightmost points for later calculations */ | |
+ /* OR - Favor ones that aren't on the top or bottom if */ | |
+ /* possible to prevent v and w from getting caught later */ | |
+ if ( segments[num_segments].x1 < leftmost_segment->x1 || | |
+ ( segments[num_segments].y > 1 && | |
+ segments[num_segments].y < height && | |
+ segments[num_segments].x1 == leftmost_segment->x1 ) ) | |
+ { | |
+ leftmost_segment->x1 = segments[num_segments].x1; | |
+ leftmost_segment->x2 = segments[num_segments].x2; | |
+ leftmost_segment->y = h; | |
+ } | |
+ if ( segments[num_segments].x2 > rightmost_segment->x2 || | |
+ ( segments[num_segments].y > 1 && | |
+ segments[num_segments].y < height && | |
+ segments[num_segments].x1 == rightmost_segment->x1 ) ) | |
+ { | |
+ rightmost_segment->x1 = segments[num_segments].x1; | |
+ rightmost_segment->x2 = segments[num_segments].x2; | |
+ rightmost_segment->y = h; | |
+ } | |
+ | |
+ if ( segments[num_segments].x1 | |
+ < leftmost_segment_not_extrema->x1 || | |
+ ( segments[num_segments].y > 1 && | |
+ segments[num_segments].y < height && | |
+ segments[num_segments].x1 | |
+ == leftmost_segment_not_extrema->x1 && | |
+ h < (FT_UInt)bitmap->rows && h > 0 ) ) | |
+ { | |
+ leftmost_segment_not_extrema->x1 = segments[num_segments].x1; | |
+ leftmost_segment_not_extrema->x2 = segments[num_segments].x2; | |
+ leftmost_segment_not_extrema->y = h; | |
+ } | |
+ if ( segments[num_segments].x2 | |
+ > rightmost_segment_not_extrema->x2 || | |
+ ( segments[num_segments].y > 1 && | |
+ segments[num_segments].y < height && | |
+ segments[num_segments].x1 | |
+ == rightmost_segment_not_extrema->x1 && | |
+ h < (FT_UInt)bitmap->rows && h > 0 ) ) | |
+ { | |
+ rightmost_segment_not_extrema->x1 = segments[num_segments].x1; | |
+ rightmost_segment_not_extrema->x2 = segments[num_segments].x2; | |
+ rightmost_segment_not_extrema->y = h; | |
+ } | |
+ | |
+ if ( segments[num_segments].x1 < leftmost_point ) | |
+ leftmost_point = segments[num_segments].x1; | |
+ | |
+ if ( segments[num_segments].x2 > rightmost_point ) | |
+ rightmost_point = segments[num_segments].x2; | |
+ | |
+ if ( segments[num_segments].x1 < leftmost_point_not_extrema && | |
+ h < (FT_UInt)bitmap->rows && h > 0 ) | |
+ leftmost_point_not_extrema = segments[num_segments].x1; | |
+ | |
+ if ( segments[num_segments].x2 > rightmost_point_not_extrema && | |
+ h < (FT_UInt)bitmap->rows && h > 0 ) | |
+ rightmost_point_not_extrema = segments[num_segments].x2; | |
+ | |
+ num_segments++; | |
+ } | |
+ /* else - other conditions - need some error checking here */ | |
+ current_value = line[xx]; | |
+ } | |
+ } | |
+ | |
+ /* initialize */ | |
+ for ( xx = 0; xx < MAX_STEMS; xx +=1 ) | |
+ { | |
+ stems[xx].center = 0; | |
+ stems[xx].count = 0; | |
+ stems[xx].width = 0; | |
+ stems[xx].height = 0; | |
+ possible_stems[xx].center = 0; | |
+ possible_stems[xx].count = 0; | |
+ possible_stems[xx].width = 0; | |
+ possible_stems[xx].height = 0; | |
+ } | |
+ | |
+ valid_stems = 0; | |
+ valid_possible_stems = 0; | |
+ | |
+ /* Determine which centers belong to stems */ | |
+ center = 0; | |
+ | |
+ while ( center < num_centers ) | |
+ { | |
+ /* slope at within which to consider a point part of a stem */ | |
+ /*const FT_UInt slope = 1; | |
+ const FT_UInt topslope = (256 * 3) / 10; */ | |
+ | |
+ /* 10 to 20 with 4 matches seems good, */ | |
+ /* but 1 or 2 with 3 stems needs to somehow get included */ | |
+ FT_Int deviation1 = 5; | |
+ FT_Int deviation2=-1, requirement1 = 4, stem_match_requirement = 3; | |
+ FT_Int center_difference_in_height; | |
+ FT_Int center_difference_in_width, valid_center_average; | |
+ FT_Int smallest_width_ledge, smallest_width_redge; | |
+ FT_Int x1_difference_in_width, x2_difference_in_width; | |
+ FT_Bool no_gap_found = FALSE; | |
+ FT_Bool no_gap_found_ledge = FALSE; | |
+ FT_Bool no_gap_found_redge = FALSE; | |
+ FT_Bool stem_detected = FALSE; | |
+ FT_Int set_width_to, set_center_to; | |
+ | |
+ /* seems to not do damage */ | |
+ /* May not be effective */ | |
+ requirement1 = height / 4; | |
+ if ( requirement1 < 5 ) | |
+ requirement1 = 5; | |
+ deviation1 = 20; | |
+ deviation2 = 20; | |
+ | |
+ if ( columns_per_pixel == 1 ) | |
+ deviation1 = deviation2 = 10; | |
+ | |
+ if ( (FT_Int)bitmap->rows <= 6 ) | |
+ deviation1 = 25; | |
+ | |
+ if ( (FT_Int)bitmap->rows <= 6 ) | |
+ deviation2 = 25; | |
+ | |
+ if ( columns_per_pixel == 1 && | |
+ (FT_Int)bitmap->rows <= 6 ) | |
+ deviation1 = deviation2 = 12; | |
+ | |
+ valid_center_average = 0; | |
+ | |
+ no_gap_found = no_gap_found_ledge = no_gap_found_redge = FALSE; | |
+ stem_detected = FALSE; | |
+ | |
+ if ( ppem < 11 ) | |
+ requirement1 = 4; | |
+ | |
+ if ( ppem > 18 ) | |
+ { | |
+ stem_match_requirement = height / 4; | |
+ if ( stem_match_requirement < 3 ) | |
+ stem_match_requirement = 3; | |
+ } | |
+ | |
+ smallest_width_ledge = smallest_width_redge = width * 256; | |
+ stem_matches = 0; | |
+ stem_matches_ledge = 0; | |
+ stem_matches_redge = 0; | |
+ last_matching_center = -1; | |
+ last_matching_ledge = -1; | |
+ last_matching_redge = -1; | |
+ | |
+ /* set currently looked at center to center value */ | |
+ this_center = center; | |
+ next_center = 0; | |
+ | |
+ /* For each center, compare with all other centers to see if others */ | |
+ /* match the properties of this one */ | |
+ while ( next_center < num_centers ) | |
+ { | |
+ | |
+ /* calculate differences */ | |
+ center_difference_in_width = abs ( centers[this_center].x | |
+ - centers[next_center].x ); | |
+ center_difference_in_height = abs ( centers[this_center].y | |
+ - centers[next_center].y ); | |
+ x1_difference_in_width = abs ( centers[this_center].x1 | |
+ - centers[next_center].x1 ); | |
+ x2_difference_in_width = abs ( centers[this_center].x2 | |
+ - centers[next_center].x2 ); | |
+ | |
+ | |
+ /* property - stem center points that align */ | |
+ /* if the center is within range, the center is less than */ | |
+ /* 1/2 the height away, and at least one edge is also within range */ | |
+ if ( center_difference_in_width | |
+ < center_difference_in_height * deviation1 && | |
+ center_difference_in_height | |
+ <= (FT_Int)bitmap->rows / 2 && | |
+ /* prevents w from getting caught ---- but also kills m */ | |
+ ( x1_difference_in_width | |
+ < center_difference_in_height * deviation2 || | |
+ x2_difference_in_width | |
+ < center_difference_in_height * deviation2 ) ) | |
+ { | |
+ stem_matches += 1; | |
+ valid_center_average += centers[next_center].x; | |
+ | |
+ /* try to find where the matching centers are far apart */ | |
+ if ( last_matching_center >= 0 && | |
+ abs( centers[last_matching_center].y | |
+ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 ) | |
+ | |
+ /* try to find where matching centers are next to each other */ | |
+ if ( last_matching_center >= 0 && | |
+ abs( centers[last_matching_center].y | |
+ - centers[next_center].y ) == 1 ) | |
+ no_gap_found = TRUE; | |
+ | |
+ last_matching_center = next_center; | |
+ } | |
+ | |
+ if ( strategy_also_use_edge_detection_for_stems ) | |
+ { | |
+ /* property - stem left edge points that align */ | |
+ /* if the center is within range, */ | |
+ /* the center is less than 1/2 the height away */ | |
+ if ( x1_difference_in_width | |
+ < center_difference_in_height * deviation1 && | |
+ center_difference_in_height <= (FT_Int)bitmap->rows / 2 ) | |
+ { | |
+ stem_matches_ledge += 1; | |
+ /* may not need for edges */ | |
+ /*valid_center_average += centers[next_center].x; */ | |
+ | |
+ if ( centers[next_center].x2 - centers[next_center].x1 | |
+ < smallest_width_ledge ) | |
+ smallest_width_ledge = centers[next_center].x2 | |
+ - centers[next_center].x1; | |
+ | |
+ /* try to find where the matching centers are far apart */ | |
+ if ( last_matching_ledge >= 0 && | |
+ abs( centers[last_matching_ledge].y | |
+ - centers[next_center].y) | |
+ >= (FT_Int)bitmap->rows / 2 ) | |
+ | |
+ /* try to find where matching centers are next to each other */ | |
+ if ( last_matching_ledge >= 0 && | |
+ abs( centers[last_matching_ledge].y | |
+ - centers[next_center].y ) == 1 ) | |
+ no_gap_found_ledge = TRUE; | |
+ last_matching_ledge = next_center; | |
+ } | |
+ } | |
+ | |
+ if ( strategy_also_use_edge_detection_for_stems ) | |
+ { | |
+ /* property - stem right edge points that align */ | |
+ /* if the center is within range, the center is less than 1/2 */ | |
+ /* the height away */ | |
+ if ( x2_difference_in_width | |
+ < center_difference_in_height * deviation1 && | |
+ center_difference_in_height | |
+ <= (FT_Int)bitmap->rows / 2 ) | |
+ { | |
+ stem_matches_redge += 1; | |
+ /* may not need for edges */ | |
+ /*valid_center_average += centers[next_center].x; */ | |
+ | |
+ if ( centers[next_center].x2 - centers[next_center].x1 | |
+ < smallest_width_redge ) | |
+ smallest_width_redge = centers[next_center].x2 | |
+ - centers[next_center].x1; | |
+ | |
+ /* try to find where the matching centers are far apart */ | |
+ if ( last_matching_redge >= 0 && | |
+ abs( centers[last_matching_redge].y | |
+ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 ) | |
+ | |
+ /* try to find where matching centers are next to each other */ | |
+ if ( last_matching_redge >= 0 && | |
+ abs( centers[last_matching_redge].y | |
+ - centers[next_center].y ) == 1 ) | |
+ no_gap_found_redge = TRUE; | |
+ | |
+ last_matching_redge = next_center; | |
+ } | |
+ } | |
+ | |
+ next_center++; | |
+ } | |
+ | |
+ if ( stem_matches > 0 ) | |
+ valid_center_average /= stem_matches; | |
+ | |
+ if ( ( stem_matches >= stem_match_requirement || | |
+ ( ( (FT_Int)bitmap->rows <= 6 || ppem < 11 ) && | |
+ stem_matches >= 2 && | |
+ abs ( valid_center_average | |
+ - centers[center].x) < deviation1 /2 ) || | |
+ /* try to catch tightly aligned stuff where the matching centers */ | |
+ /* are next to each other only */ | |
+ ( stem_matches == 2 && | |
+ abs( valid_center_average | |
+ - centers[center].x) <= deviation1 /2 && | |
+ no_gap_found && | |
+ ppem < 18 ) ) && | |
+ /* catches things like times 16 u but gets a lot of w's too */ | |
+ /* stem width is less than 1/3 of the bitmap width, */ | |
+ /* or bitmap_width is small */ | |
+ ( centers[center].x2 - centers[center].x1 | |
+ < (m_horiAdvance * 12) / 2 || | |
+ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) ) | |
+ { | |
+ stem_detected = TRUE; | |
+ set_width_to = centers[center].x2 - centers[center].x1; | |
+ set_center_to = centers[center].x; | |
+ } | |
+ | |
+ /* see if edges found anything */ | |
+ if ( strategy_also_use_edge_detection_for_stems && !stem_detected ) | |
+ { | |
+ /* Require no gap for edges */ | |
+ /* stem width less than 1/3 bitmap width, or bitmap_width is small */ | |
+ /* The stem occurs on the left side of glyph only */ | |
+ if ( ( stem_matches_ledge >= stem_match_requirement && | |
+ no_gap_found_ledge ) && | |
+ ( centers[center].x2 - centers[center].x1 | |
+ < ( m_horiAdvance * 12 ) / 2 || | |
+ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) && | |
+ centers[center].x < ( m_horiAdvance * 12 ) / 2 ) | |
+ { | |
+ stem_detected = TRUE; | |
+ set_width_to = smallest_width_ledge; | |
+ set_center_to = centers[center].x1 + set_width_to / 2; | |
+ stem_matches = stem_matches_ledge; | |
+ } | |
+ /* Require no gap for edges */ | |
+ /* stem width is less than 1/3 bitmap width, or bitmap_width is small */ | |
+ /* The stem occurs on the right side of glyph only */ | |
+ else if ( ( stem_matches_redge >= stem_match_requirement && | |
+ no_gap_found_redge ) && | |
+ ( centers[center].x2 - centers[center].x1 | |
+ < ( m_horiAdvance * 12 ) / 2 || | |
+ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) && | |
+ centers[center].x > (m_horiAdvance * 12) / 2 ) | |
+ { | |
+ stem_detected = TRUE; | |
+ set_width_to = smallest_width_redge; | |
+ set_center_to = centers[center].x2 - set_width_to / 2; | |
+ stem_matches = stem_matches_redge; | |
+ } | |
+ } | |
+ | |
+ | |
+ /*store and/or replace highest occurrences with 3 or more centers */ | |
+ /* because this matched, it will become the top dog regardless */ | |
+ if ( stem_detected && (stem_matches > possible_stems[0].height) ) | |
+ { | |
+ /* if this is the first stem just go ahead */ | |
+ if ( valid_possible_stems == 0 ) | |
+ { | |
+ valid_possible_stems = 1; | |
+ possible_stems[0].center = set_center_to; | |
+ possible_stems[0].count = stem_matches; | |
+ possible_stems[0].width = set_width_to; | |
+ possible_stems[0].height = stem_matches; | |
+ } | |
+ | |
+ /* otherwise, if there is already a stem */ | |
+ else if ( valid_possible_stems == 1 ) | |
+ { | |
+ /* if stem is within range of existing one, replace existing one */ | |
+ | |
+ /* if the stem isn't within the range of this one swap it with */ | |
+ /* next one first */ | |
+ if ( abs ( set_center_to - possible_stems[0].center ) | |
+ >= one_pixel * 2 ) | |
+ { | |
+ swap_stem ( &possible_stems[0], &possible_stems[1] ); | |
+ valid_possible_stems = 2; | |
+ } | |
+ possible_stems[0].center = set_center_to; | |
+ possible_stems[0].count = stem_matches; | |
+ possible_stems[0].width = set_width_to; | |
+ possible_stems[0].height = stem_matches; | |
+ } | |
+ | |
+ /* otherwise if there are already 2 stems */ | |
+ else if ( valid_possible_stems >= 2 ) | |
+ { | |
+ /* if the stem is within the range of existing one, replace */ | |
+ /* existing one */ | |
+ if ( abs ( set_center_to - possible_stems[0].center ) | |
+ <= one_pixel * 2 ) | |
+ { | |
+ possible_stems[0].center = set_center_to; | |
+ possible_stems[0].count = stem_matches; | |
+ possible_stems[0].width = set_width_to; | |
+ possible_stems[0].height = stem_matches; | |
+ } | |
+ /* if the stem isn't within the range of this one */ | |
+ else | |
+ { | |
+ /* see if within range of next one and swap if so and proceed */ | |
+ /* overwriting it */ | |
+ if ( abs ( set_center_to - possible_stems[1].center ) | |
+ <= one_pixel * 2 ) | |
+ swap_stem ( &possible_stems[0], &possible_stems[1] ); | |
+ | |
+ /* otherwise see if in range of third one */ | |
+ else if ( abs ( set_center_to - possible_stems[2].center ) | |
+ <= one_pixel * 2 ) | |
+ swap_stem ( &possible_stems[0], &possible_stems[2] ); | |
+ | |
+ /* otherwise this is the new top dog, so demote everything */ | |
+ else | |
+ { | |
+ swap_stem ( &possible_stems[1], &possible_stems[2] ); | |
+ swap_stem ( &possible_stems[0], &possible_stems[1] ); | |
+ valid_possible_stems += 1; | |
+ } | |
+ possible_stems[0].center = set_center_to; | |
+ possible_stems[0].count = stem_matches; | |
+ possible_stems[0].width = set_width_to; | |
+ possible_stems[0].height = stem_matches; | |
+ } | |
+ } | |
+ } | |
+ else if ( stem_matches > possible_stems[1].height && | |
+ set_center_to != 0 ) | |
+ { | |
- /* When accumulating the oversampled spans we need to assure that */ | |
- /* fully covered pixels are equal to 255 and do not overflow. */ | |
- /* It is important that the SCALE is a power of 2, each subpixel */ | |
- /* cover can also reach a power of 2 after rounding, and the total */ | |
- /* is clamped to 255 when it adds up to 256. */ | |
- for ( ; count--; spans++ ) | |
+ /* make sure it doesn't match the first stem */ | |
+ if ( abs ( set_center_to - possible_stems[0].center ) >= one_pixel * 2 ) | |
{ | |
- cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); | |
- for ( x = 0; x < spans->len; x++ ) | |
+ | |
+ /* if this is the second stem */ | |
+ if ( valid_possible_stems == 1 ) | |
+ valid_possible_stems = 2; | |
+ | |
+ /* otherwise if there is already a stem here */ | |
+ else if ( valid_possible_stems >= 2 ) | |
+ { | |
+ /* if it doesn't match the second stem, proceed to swap out */ | |
+ /* with the third. if it does, replace it */ | |
+ if ( abs ( set_center_to - possible_stems[1].center ) | |
+ >= one_pixel * 2 ) | |
{ | |
- sum = dst[( spans->x + x ) / SCALE] + cover; | |
- dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); | |
+ swap_stem ( &possible_stems[1], &possible_stems[2] ); | |
+ valid_possible_stems +=1; | |
} | |
} | |
+ possible_stems[1].center = set_center_to; | |
+ possible_stems[1].count = stem_matches; | |
+ possible_stems[1].width = set_width_to; | |
+ possible_stems[1].height = stem_matches; | |
+ } | |
} | |
+ else if ( stem_matches > possible_stems[2].height && | |
+ set_center_to != 0 ) | |
+ { | |
+ /* if it doesn't match the first or second one */ | |
+ if ( abs( set_center_to - possible_stems[0].center) >= one_pixel * 2 && | |
+ abs( set_center_to - possible_stems[1].center) >= one_pixel * 2 ) | |
+ { | |
+ if ( valid_possible_stems == 2 ) | |
+ valid_possible_stems += 1; | |
- static FT_Error | |
- ft_smooth_raster_overlap( FT_Renderer render, | |
- FT_Outline* outline, | |
- FT_Bitmap* bitmap ) | |
+ possible_stems[2].center = set_center_to; | |
+ possible_stems[2].count = stem_matches; | |
+ possible_stems[2].width = set_width_to; | |
+ possible_stems[1].height = stem_matches; | |
+ } | |
+ } | |
+ | |
+ if ( valid_possible_stems > 3 ) | |
+ valid_possible_stems = 3; | |
+ | |
+ center++; | |
+ } | |
+ | |
+ /* promote to stem */ | |
+ if ( valid_possible_stems > 0 ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- FT_Vector* points = outline->points; | |
- FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); | |
- FT_Vector* vec; | |
+ stems[0].center = possible_stems[0].center; | |
+ stems[0].count = possible_stems[0].count; | |
+ stems[0].width = possible_stems[0].width; | |
+ stems[0].height = possible_stems[0].height; | |
+ stems[0].generated = FALSE; | |
+ valid_stems++; | |
+ } | |
- FT_Raster_Params params; | |
- TOrigin target; | |
+ if ( valid_stems == 1 && | |
+ valid_possible_stems > 1 ) | |
+ { | |
+ stems[1].center = possible_stems[1].center; | |
+ stems[1].count = possible_stems[1].count; | |
+ stems[1].width = possible_stems[1].width; | |
+ stems[1].height = possible_stems[1].height; | |
+ stems[1].generated = FALSE; | |
+ valid_stems++; | |
+ } | |
+ if ( valid_stems == 2 && | |
+ valid_possible_stems > 2 && | |
+ possible_stems[2].center != 0 ) | |
+ { | |
+ stems[2].center = possible_stems[2].center; | |
+ stems[2].count = possible_stems[2].count; | |
+ stems[2].width = possible_stems[2].width; | |
+ stems[2].height = possible_stems[2].height; | |
+ stems[2].generated = FALSE; | |
+ valid_stems++; | |
+ } | |
- /* Reject outlines that are too wide for 16-bit FT_Span. */ | |
- /* Other limits are applied upstream with the same error code. */ | |
- if ( bitmap->width * SCALE > 0x7FFF ) | |
- return FT_THROW( Raster_Overflow ); | |
+ /* sort stems in x direction */ | |
+ if ( valid_stems == 3 ) | |
+ { | |
+ if ( stems[0].center > stems[1].center ) | |
+ swap_stem ( &stems[0], &stems[1] ); | |
- /* Set up direct rendering to average oversampled spans. */ | |
- params.source = outline; | |
- params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; | |
- params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans; | |
- params.user = ⌖ | |
+ if ( stems[0].center > stems[2].center ) | |
+ swap_stem ( &stems[1], &stems[2] ); | |
+ | |
+ if ( stems[1].center > stems[2].center ) | |
+ swap_stem ( &stems[1], &stems[2] ); | |
+ | |
+ if ( stems[0].center > stems[1].center ) | |
+ swap_stem ( &stems[0], &stems[1] ); | |
+ | |
+ /* only look at first and last stem for now */ | |
+ swap_stem ( &stems[1], &stems[2] ); | |
+ } | |
+ | |
+ /* synthesize stems - Works, but needs work */ | |
+ if ( ( strategy_synthesize_stems || | |
+ known_stem_values->synth_stems ) && | |
+ valid_stems == 0 && | |
+ ppem > 10 ) | |
+ { | |
+ /* if the leftmost segment's leftmost point is the same as the glyph's */ | |
+ /* leftmost point, and it is of reasonable width, and is not on the */ | |
+ /* top or bottom of the bitmap */ | |
+ if ( leftmost_segment_not_extrema->x1 | |
+ == leftmost_point_not_extrema && | |
+ abs ( leftmost_segment_not_extrema->x2 | |
+ - leftmost_segment_not_extrema->x1 ) | |
+ < ( rightmost_point_not_extrema | |
+ - leftmost_point_not_extrema ) / 3 && | |
+ leftmost_segment_not_extrema->y < height && | |
+ leftmost_segment_not_extrema->y > 1 ) | |
+ { | |
+ stems[valid_stems].center = ( leftmost_segment_not_extrema->x2 | |
+ + leftmost_segment_not_extrema->x1 ) / 2; | |
+ stems[valid_stems].width = leftmost_segment_not_extrema->x2 | |
+ - leftmost_segment_not_extrema->x1; | |
+ stems[valid_stems].generated = TRUE; | |
+ valid_stems += 1; | |
+ } | |
+ | |
+ | |
+ if ( rightmost_segment_not_extrema->x2 | |
+ == rightmost_point_not_extrema && | |
+ abs ( rightmost_segment_not_extrema->x2 | |
+ - rightmost_segment_not_extrema->x1 ) | |
+ < ( rightmost_point_not_extrema | |
+ - leftmost_point_not_extrema ) / 3 && | |
+ rightmost_segment_not_extrema->y < height && | |
+ rightmost_segment_not_extrema->y > 1 ) | |
+ { | |
+ stems[valid_stems].center = ( rightmost_segment_not_extrema->x2 | |
+ + rightmost_segment_not_extrema->x1 ) / 2; | |
+ stems[valid_stems].width = rightmost_segment_not_extrema->x2 | |
+ - rightmost_segment_not_extrema->x1; | |
+ stems[valid_stems].generated = TRUE; | |
+ valid_stems += 1; | |
+ } | |
+ | |
+ } | |
+ | |
+ /* sort stems in x direction */ | |
+ if ( valid_stems > 1 && stems[0].center > stems[1].center ) | |
+ swap_stem ( &stems[0], &stems[1] ); | |
+ | |
+ if ( valid_stems == 0 && known_stem_values->stem_translating != 0 ) | |
+ { | |
+ *translate_value += known_stem_values->stem_translating; | |
+ | |
+ if ( strategy_use_strengths ) | |
+ { | |
+ /* consider 1/2 pixel the max when strength is at 100%, | |
+ unless translate is already greater than that */ | |
+ FT_Int strength_cutoff = 32; | |
+ | |
+ | |
+ if ( abs ( *translate_value ) > strength_cutoff) | |
+ strength_cutoff = *translate_value; | |
+ | |
+ max_strength = ( strength_cutoff * alignment_strength ) / 100; | |
+ | |
+ if ( *translate_value < -max_strength ) | |
+ *translate_value = -max_strength; | |
+ else if ( *translate_value > max_strength ) | |
+ *translate_value = max_strength; | |
+ } | |
+ } | |
+ else | |
+ /* Start snapping */ | |
+ { | |
+ FT_Int center_offset; | |
+ FT_Int modulus; | |
+ FT_Int delta, delta2; | |
+ FT_Long stem_distance = 1, new_distance = 1; | |
+ FT_Int distance_floor, distance_ceiling; | |
+ FT_Int translate_value2 = 0; | |
+ FT_Int main_stem = 0; | |
+ FT_Int lbearing = m_horiBearingX * 12; | |
+ FT_Int bitmap_stem_location = stems[0].center; | |
+ FT_Int advance_stem_location = bitmap_stem_location | |
+ + lbearing - one_pixel; | |
+ FT_Int advance_width = m_horiAdvance * 12; | |
+ FT_Int original_advance_width = 12 * ( slot->linearHoriAdvance >> 10 ); | |
+ FT_Int glyph_width = rightmost_point - leftmost_point; | |
+ FT_Int stem_width = stems[0].width; | |
+ FT_Int advance_leftmost_location = leftmost_point | |
+ + lbearing - one_pixel; | |
+ FT_Int advance_rightmost_location = rightmost_point | |
+ + lbearing - one_pixel; | |
+ | |
+#define proposed_transformed_point(point) \ | |
+ point * (float)(new_distance) / (float)(stem_distance) \ | |
+ + *translate_value * 12 - ( stems[main_stem].center * (float)(new_distance) \ | |
+ / (float)(stem_distance) - stems[main_stem].center) | |
+ | |
+#define proposed_translated_point(point) point + *translate_value * 12 | |
- params.clip_box.xMin = 0; | |
- params.clip_box.yMin = 0; | |
- params.clip_box.xMax = bitmap->width * SCALE; | |
- params.clip_box.yMax = bitmap->rows * SCALE; | |
+ center_offset = one_pixel / 2; /* half pixel */ | |
+ modulus = one_pixel; /* whole pixel */ | |
- if ( bitmap->pitch < 0 ) | |
- target.origin = bitmap->buffer; | |
+ /* Determine center_offset via known values */ | |
+ if ( known_stem_values->stem_width >= 0 ) | |
+ { | |
+ if ( known_stem_values->stem_width % 2 == 0 ) | |
+ center_offset = 0; | |
else | |
- target.origin = bitmap->buffer | |
- + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; | |
+ center_offset = one_pixel / 2; | |
+ } | |
+ /* otherwise do intelligent guessing, if set */ | |
+ else if ( strategy_auto_change_center_offset && | |
+ ppem >= STEM_WIDTH_2_PPEM && | |
+ stems[0].width < one_pixel * 1.45 ) | |
+ center_offset = one_pixel / 2; | |
+ else if ( strategy_auto_change_center_offset && | |
+ ppem >= STEM_WIDTH_2_PPEM && | |
+ stems[0].width >= one_pixel * 1.45 && | |
+ stems[0].width < one_pixel * 2.6 ) | |
+ center_offset = 0; | |
+ else if ( strategy_auto_change_center_offset && | |
+ ppem >= STEM_WIDTH_2_PPEM && | |
+ stems[0].width >= one_pixel * 2.6 && | |
+ stems[0].width < one_pixel * 3.6 ) | |
+ center_offset = one_pixel / 2; | |
+ else if ( strategy_auto_change_center_offset && | |
+ ppem >= STEM_WIDTH_2_PPEM ) | |
+ center_offset = | |
+ ( one_pixel | |
+ * ( ( ( (int)( stems[0].width + one_pixel / 2 ) ) | |
+ / one_pixel ) % 2 ) ) / 2; | |
+ | |
+ /* Snap to closest translate and scale values by default */ | |
+ if ( valid_stems >= 1 ) | |
+ { | |
+ /* closest snapping point for stem 0 */ | |
+ delta = ( stems[0].center + center_offset ) % modulus; | |
+ | |
+ if ( delta < modulus / 2 ) | |
+ /* snap left */ | |
+ *translate_value = -delta / ( columns_per_pixel * 4 ); | |
+ else | |
+ /* snap right */ | |
+ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 ); | |
+ } | |
- target.pitch = bitmap->pitch; | |
+ if ( strategy_use_d_correction ) | |
+ { | |
+ /* if the only stem is in the last 1/3 of glyph width, the advance */ | |
+ /* is 6 pixels, the ppem 11, and doing so doesn't violate bitmap , */ | |
+ /* boundaries force it to snap right */ | |
+ if ( valid_stems == 1 && | |
+ advance_stem_location > (advance_width * 2) / 3 && | |
+ advance_width == 6 * one_pixel && | |
+ rightmost_point + modulus - delta | |
+ <= ( width - (columns_per_pixel * 2) / 3) * 256 && | |
+ ppem == 11 ) | |
+ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 ); | |
+ } | |
- /* inflate outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
+ if ( strategy_use_strengths ) | |
{ | |
- vec->x *= SCALE; | |
- vec->y *= SCALE; | |
+ /* consider 1/2 pixel the max when strength is at 100%, | |
+ unless translate is already greater than that */ | |
+ FT_Int strength_cutoff = 32; | |
+ if ( abs ( *translate_value ) > strength_cutoff ) | |
+ strength_cutoff = *translate_value; | |
+ | |
+ max_strength = ( strength_cutoff * alignment_strength ) / 100; | |
+ | |
+ if ( *translate_value < -max_strength ) | |
+ *translate_value = -max_strength; | |
+ else if ( *translate_value > max_strength ) | |
+ *translate_value = max_strength; | |
} | |
- /* render outline into the bitmap */ | |
- error = render->raster_render( render->raster, ¶ms ); | |
+ /* If 2 stems is detected, scale distance | |
+ between in order to land on pixels */ | |
+ if ( valid_stems >= 2 ) | |
+ { | |
+ stem_distance = abs ( stems[1].center - stems[0].center ); | |
- /* deflate outline */ | |
- for ( vec = points; vec < points_end; vec++ ) | |
+ delta = stem_distance % modulus; | |
+ new_distance = stem_distance - delta; | |
+ | |
+ distance_floor = stem_distance - delta; | |
+ distance_ceiling = stem_distance + ( modulus - delta ); | |
+ | |
+ if ( delta < modulus / 2 ) | |
+ new_distance = distance_floor; | |
+ else | |
+ new_distance = distance_ceiling; | |
+ | |
+ if ( columns_per_pixel == 3 && | |
+ valid_stems == 3 && | |
+ strategy_use_m_control && | |
+ ( width - 2 * columns_per_pixel ) > 6 * columns_per_pixel && | |
+ ppem > 8 && | |
+ ( advance_stem_location - advance_leftmost_location ) | |
+ < stems[main_stem].width * 2 ) | |
+ { | |
+ /* Possibly use 2 only when compatible widths is on? */ | |
+ FT_Int mod_factor = 2; | |
+ | |
+ if ( verbose ) | |
+ printf ( "USING M CONTROL "); | |
+ | |
+ distance_floor = stem_distance | |
+ - stem_distance % ( modulus * mod_factor ) ; | |
+ distance_ceiling = distance_floor + modulus * mod_factor; | |
+ | |
+ new_distance = distance_ceiling; | |
+ | |
+ /* force certain ideal situations */ | |
+ /* these 2 are mostly safe to do */ | |
+ if ( distance_ceiling | |
+ + one_pixel * columns_per_pixel == advance_width && | |
+ stem_width < one_pixel * 1.25 ) | |
+ new_distance = distance_ceiling; | |
+ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER | |
+ THAT NUDGE IS UP OR DOWN */ | |
+ else if ( stem_distance + one_pixel * 2.6 >= advance_width && | |
+ stem_width < one_pixel * 1.25 ) | |
+ new_distance = distance_ceiling; | |
+ | |
+ if ( proposed_transformed_point ( leftmost_point ) | |
+ < one_third_pixel * 2 || | |
+ proposed_transformed_point ( rightmost_point ) | |
+ > ( width -2 ) * one_third_pixel ) | |
+ new_distance = distance_floor; | |
+ | |
+ /* NEED TO IGNORE SERIF Ms HERE */ | |
+ /* perhaps check bitmap boundaries instead??? */ | |
+ if ( strategy_bearing_correction && new_distance == distance_ceiling ) | |
+ { | |
+ /* Correct if bearings are made substantially worse | |
+ (more than 1/3 a pixel beyond advance) */ | |
+ if ( proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_width + one_third_pixel && | |
+ proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_rightmost_location && | |
+ -proposed_transformed_point( advance_leftmost_location ) | |
+ < advance_rightmost_location - advance_width ) | |
+ new_distance = distance_floor; | |
+ } | |
+ | |
+ if ( known_stem_values->m >= 0 ) | |
{ | |
- vec->x /= SCALE; | |
- vec->y /= SCALE; | |
+ if ( known_stem_values->m == 0 ) | |
+ new_distance = distance_floor; | |
+ else | |
+ new_distance = distance_ceiling; | |
} | |
- return error; | |
+ if ( ( rightmost_point - leftmost_point) - | |
+ ( ( rightmost_point * *scale_value) | |
+ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 ) | |
+ { | |
+ *scale_value = 1.0; | |
+ *translate_value = 0; | |
+ goto Exit; | |
+ } | |
+ | |
+ } | |
+ else if ( columns_per_pixel == 1 && | |
+ valid_stems == 3 && | |
+ strategy_use_m_control && valid_stems == 3 && | |
+ width >= 6 * columns_per_pixel && | |
+ ppem > 8 && | |
+ ( advance_stem_location - advance_leftmost_location ) | |
+ < stems[main_stem].width * 2 ) | |
+ { | |
+ /* Possibly use 2 only when compatible widths is on? */ | |
+ FT_Int mod_factor = 2; | |
+ | |
+ if ( verbose ) | |
+ printf ("USING M CONTROL "); | |
+ distance_floor = stem_distance - stem_distance | |
+ % ( modulus * mod_factor) ; | |
+ distance_ceiling = distance_floor + modulus * mod_factor; | |
+ | |
+ new_distance = distance_ceiling; | |
+ | |
+ /* force certain ideal situations */ | |
+ /* these 2 are mostly safe to do */ | |
+ if ( distance_ceiling | |
+ + one_pixel * columns_per_pixel == advance_width && | |
+ stem_width < one_pixel * 1.25 ) | |
+ new_distance = distance_ceiling; | |
+ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER | |
+ THAT NUDGE IS UP OR DOWN */ | |
+ else if ( stem_distance + one_pixel * 2.6 >= advance_width && | |
+ stem_width < one_pixel * 1.25 ) | |
+ new_distance = distance_ceiling; | |
+ | |
+ if ( proposed_transformed_point( leftmost_point ) < 0 || | |
+ proposed_transformed_point( rightmost_point ) | |
+ > width * one_pixel - 2 * one_third_pixel ) | |
+ new_distance = distance_floor; | |
+ | |
+ /* NEED TO IGNORE SERIF Ms HERE */ | |
+ /* perhaps check bitmap boundaries instead??? */ | |
+ if ( strategy_bearing_correction && new_distance == distance_ceiling ) | |
+ { | |
+ /* Correct if bearings are made substantially worse | |
+ (more than 1/3 a pixel beyond advance) */ | |
+ if ( proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_width + one_third_pixel && | |
+ proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_rightmost_location && | |
+ -proposed_transformed_point( advance_leftmost_location ) | |
+ < advance_rightmost_location - advance_width ) | |
+ new_distance = distance_floor; | |
+ } | |
+ | |
+ if ( known_stem_values->m >= 0 ) | |
+ { | |
+ if ( known_stem_values->m == 0 ) | |
+ new_distance = distance_floor; | |
+ else | |
+ new_distance = distance_ceiling; | |
+ } | |
+ | |
+ | |
+ if ( ( rightmost_point - leftmost_point ) | |
+ - ( ( rightmost_point * *scale_value ) | |
+ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 ) | |
+ { | |
+ *scale_value = 1.0; | |
+ *translate_value = 0; | |
+ goto Exit; | |
+ } | |
+ | |
+ } | |
+ else | |
+ { | |
+ if ( strategy_fit_to_width ) | |
+ new_distance = advance_width - 3 * one_pixel; | |
+ else if ( known_stem_values->stem_scaling >= 0 ) | |
+ { | |
+ if ( known_stem_values->stem_scaling > 0 ) | |
+ new_distance = distance_ceiling; | |
+ else | |
+ new_distance = distance_floor; | |
+ | |
+ /* enforce advance width boundaries */ | |
+ /* TOO RESTRICTIVE ON SERIF FONTS */ | |
+ if ( proposed_transformed_point( advance_rightmost_location ) | |
+ >= advance_width || | |
+ proposed_transformed_point( advance_leftmost_location ) | |
+ <= 0 ) | |
+ new_distance = distance_floor; | |
+ | |
+ /* enforce literal bitmap boundaries if no translate room */ | |
+ if ( ( proposed_transformed_point(rightmost_point) >= width * 256 | |
+ || proposed_transformed_point(leftmost_point ) <= one_pixel ) | |
+ && new_distance + one_pixel * 3 > advance_width ) | |
+ new_distance = distance_floor; | |
+ | |
+ } | |
+ else if ( strategy_translate_using_closest_stem ) | |
+ { | |
+ /* closest snapping point for stem 1 */ | |
+ delta2 = ( stems[1].center + center_offset ) % modulus; | |
+ | |
+ if ( delta2 < modulus / 2 ) | |
+ /* snap left */ | |
+ translate_value2 = -delta2 / ( columns_per_pixel * 4 ); | |
+ else | |
+ /* snap right */ | |
+ translate_value2 = ( modulus - delta2 ) | |
+ / ( columns_per_pixel * 4 ); | |
+ | |
+ if ( abs ( translate_value2 ) < abs ( *translate_value ) ) | |
+ { | |
+ *translate_value = translate_value2; | |
+ main_stem = 1; | |
+ } | |
+ | |
+ } | |
+ else if ( strategy_scale_to_closest_centers ) | |
+ { | |
+ /* closest snapping point for stem 0 */ | |
+ delta = ( stems[0].center + center_offset ) % modulus; | |
+ delta2 = ( stems[1].center + center_offset ) % modulus; | |
+ | |
+ if ( delta < modulus / 2 ) | |
+ /* stretch left */ | |
+ new_distance = delta + stem_distance; | |
+ else | |
+ /* stretch right */ | |
+ new_distance = delta - modulus + stem_distance; | |
+ | |
+ if ( delta2 < modulus / 2 ) | |
+ new_distance -= delta2; /* stretch left */ | |
+ else | |
+ new_distance += modulus - delta2; /* stretch right */ | |
+ | |
+ } | |
+ else if ( strategy_scale_to_closest_centers_up_only ) | |
+ { | |
+ FT_Int net_change = 0; | |
+ | |
+ /* closest snapping point for stem 0 */ | |
+ delta = ( stems[0].center + center_offset ) % modulus; | |
+ delta2 = ( stems[1].center + center_offset ) % modulus; | |
+ | |
+ if ( delta < modulus / 2 ) | |
+ net_change = delta; /* stretch left */ | |
+ else | |
+ net_change = -( modulus - delta ); /* stretch right */ | |
+ | |
+ if ( delta2 < modulus / 2 ) | |
+ net_change -= delta2; /* stretch left */ | |
+ else | |
+ net_change += modulus - delta2; /* stretch right */ | |
+ | |
+ if ( net_change > 0 && | |
+ proposed_transformed_point( advance_rightmost_location ) | |
+ < advance_width && | |
+ proposed_transformed_point( advance_leftmost_location ) > 0 ) | |
+ new_distance = distance_ceiling; | |
+ } | |
+ | |
+ else if ( strategy_always_use_distance_ceiling ) | |
+ { | |
+ if ( proposed_transformed_point( advance_rightmost_location ) | |
+ < advance_width && | |
+ proposed_transformed_point( advance_leftmost_location ) > 0 ) | |
+ new_distance = distance_ceiling; | |
+ } | |
+ } | |
+ | |
+ if ( strategy_use_strengths ) | |
+ { | |
+ FT_Int strength_cutoff = center_offset; | |
+ | |
+ | |
+ delta2 = new_distance - stem_distance; | |
+ | |
+ if ( abs ( delta2 ) > strength_cutoff ) | |
+ strength_cutoff = delta2; | |
+ | |
+ max_strength = ( strength_cutoff * fitting_strength ) / 100; | |
+ | |
+ if ( delta2 < -max_strength ) | |
+ new_distance = stem_distance - max_strength; | |
+ else if ( delta2 > max_strength ) | |
+ new_distance = stem_distance + max_strength; | |
+ } | |
+ | |
+ *scale_value = (float)( new_distance ) / (float)( stem_distance ); | |
+ *translate_value = *translate_value | |
+ - ( (float)( stems[main_stem].center * (float)new_distance ) | |
+ / (float)stem_distance - stems[main_stem].center ) / 12; | |
+ | |
+ if ( valid_stems == 2 ) | |
+ *embolden_value = ( 64.0 / *scale_value - 64.0 ); | |
+ | |
+ if ( valid_stems == 3 ) | |
+ *embolden_value = ( 64.0 / *scale_value - 64.0 ) / 1.5; | |
+ } | |
+ | |
+ if ( verbose ) | |
+ printf ( "%lu stems:", valid_stems ); | |
+ | |
+ if ( valid_stems == 1 && verbose ) | |
+ printf ( "1 stem: bitmapwidth:%d glyphwidth:%f glyph_width:%f center:%f bearing:%f advance:%f lhadvance:%f stemwidth:%f %d %d", | |
+ (width - 6) / columns_per_pixel, | |
+ (float)m_width / 64.0, | |
+ (float)glyph_width / (float)one_pixel, | |
+ (float)( (float)advance_stem_location ) / (float)one_pixel, | |
+ (float)m_horiBearingX / 64.0, | |
+ (float)m_horiAdvance / 64.0, | |
+ (float)linearHoriAdvance / 64.0, | |
+ (float)stems[0].width / (float)one_pixel, | |
+ advance_width, original_advance_width ); | |
+ else if ( valid_stems >= 2 && verbose ) | |
+ printf ( "%lu stems: bitmapwidth:%d center1:%f center2:%f difference:%f bearing:%f advance:%f advstemloc:%f ", | |
+ valid_stems, | |
+ (width - 6) / columns_per_pixel, | |
+ ( (float)advance_stem_location ) / (float)one_pixel, | |
+ ( (float)advance_stem_location | |
+ + (float)abs ( stems[1].center | |
+ - stems[0].center) ) / (float)one_pixel, | |
+ ( (float)abs ( stems[1].center | |
+ - stems[0].center ) ) / (float)one_pixel, | |
+ (float)m_horiBearingX / 64.0, | |
+ (float)m_horiAdvance / 64.0, | |
+ (float)advance_stem_location / (float)one_pixel ); | |
+ | |
+ if ( strategy_bearing_correction ) | |
+ { | |
+ /* Correct if negative bearings are made substantially worse */ | |
+ /* (more than 1/3 a pixel) */ | |
+ if ( proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_width && | |
+ proposed_transformed_point( advance_rightmost_location ) | |
+ > advance_rightmost_location && | |
+ -proposed_transformed_point( advance_leftmost_location ) | |
+ < advance_rightmost_location - advance_width && | |
+ *translate_value | |
+ > one_third_pixel / ( columns_per_pixel * 4 ) ) | |
+ { | |
+ *translate_value -=64 ; | |
+ if ( verbose ) | |
+ printf ( "TRANSLATING -64 " ); | |
+ } | |
+ } | |
+ goto Exit; | |
+ } | |
+ | |
+ Exit: | |
+ | |
+#define transformed_point( point ) point * *scale_value + *translate_value * 12 | |
+ | |
+ if ( strategy_correct_out_of_bounds_outlines ) | |
+ { | |
+ /* Correct if outside bitmap */ | |
+ if ( transformed_point( rightmost_point ) | |
+ >= width * 256 - 2 * one_third_pixel && | |
+ transformed_point( leftmost_point ) | |
+ > one_pixel + 2 * one_third_pixel ) | |
+ *translate_value -=64 ; | |
+ else if ( transformed_point( leftmost_point ) | |
+ <= one_pixel / 2 && | |
+ transformed_point( rightmost_point ) | |
+ <= width * 256 - ( one_pixel + one_pixel / 2 ) ) | |
+ *translate_value += 64; | |
+ } | |
+ | |
+ STVALUES | |
+ free ( centers ); | |
+ free ( segments ); | |
+ free ( stem_centers ); | |
+ free ( stems ); | |
+ free ( leftmost_segment ); | |
} | |
-#undef SCALE | |
+ /* Gamma correction */ | |
+ static void | |
+ _ft_lcd_gamma_correction_correction ( FT_Bitmap* bitmap, | |
+ FT_Render_Mode mode, | |
+ FT_GlyphSlot slot, | |
+ float gamma_correction_lt, | |
+ float gamma_correction_value ) | |
+ { | |
+ if ( gamma_correction_value != 1.0 ) | |
+ { | |
+ FT_UInt width = (FT_UInt)bitmap->width; | |
+ FT_UInt height = (FT_UInt)bitmap->rows; | |
+ FT_Byte* line = bitmap->buffer; | |
+ float ppem = (float)slot->face->size->metrics.x_ppem; | |
+ | |
+ | |
+ if ( !slot->face || !slot->face->size ) return; | |
+ | |
+ if ( ppem >= 5 ) | |
+ for ( height = (FT_UInt)bitmap->rows; | |
+ height > 0; | |
+ height--, line += bitmap->pitch ) | |
+ { | |
+ FT_UInt xx; | |
+ | |
+ | |
+ for ( xx = 0; xx < width; xx += 1 ) | |
+ { | |
+ /*normal*/ | |
+ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value );*/ | |
+ | |
+ /* sloped */ | |
+ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5 | |
+ * (1-gamma_correction_value)/(gamma_correction_lt -5) | |
+ + ((1-gamma_correction_value)/(gamma_correction_lt -5)) * ppem );*/ | |
+ | |
+ /* 1/3-sloped */ | |
+ line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5 | |
+ * ( ( 1 - gamma_correction_value ) | |
+ / ( 3 * ( gamma_correction_lt -5 ) ) ) | |
+ + ( ( 1 - gamma_correction_value ) | |
+ / ( 3 * ( gamma_correction_lt -5) ) ) * ppem ); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+#endif | |
+ | |
+ /* convert a slot's glyph image into a bitmap */ | |
static FT_Error | |
- ft_smooth_render( FT_Renderer render, | |
+ ft_smooth_render_generic( FT_Renderer render, | |
FT_GlyphSlot slot, | |
FT_Render_Mode mode, | |
- const FT_Vector* origin ) | |
+ const FT_Vector* origin, | |
+ FT_Render_Mode required_mode ) | |
{ | |
- FT_Error error = FT_Err_Ok; | |
- FT_Outline* outline = &slot->outline; | |
+ FT_Error error; | |
+ FT_Outline* outline = NULL; | |
+ FT_Outline* outline_orig = NULL; | |
+ FT_BBox cbox; | |
+ FT_Pos width, height, pitch, ppem; | |
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ FT_Pos height_org, width_org; | |
+#endif | |
FT_Bitmap* bitmap = &slot->bitmap; | |
FT_Memory memory = render->root.memory; | |
+ FT_Int hmul = ( mode == FT_RENDER_MODE_LCD ); | |
+ FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V ); | |
FT_Pos x_shift = 0; | |
FT_Pos y_shift = 0; | |
+ FT_Pos x_left, y_top; | |
+ | |
+ FT_Raster_Params params; | |
+ | |
+ FT_Bool have_translated_origin = FALSE; | |
+ FT_Bool have_outline_shifted = FALSE; | |
+ FT_Bool have_buffer = FALSE; | |
+ | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ FT_Matrix scaleMat; | |
+ FT_Long translate_value = 0; | |
+ float scale_value = 1.0; | |
+ FT_Int align_called = 0; | |
+ | |
+ | |
+ int chromeos_style_sharpening_strength = 0; | |
+ int alignment_strength = 0; | |
+ int fitting_strength = 0; | |
+ int fringe_filter_strength = 0; | |
+ int grayscale_filter_strength = 0; | |
+ | |
+ int autohint_horizontal_stem_darken_strength = 0; | |
+ int autohint_vertical_stem_darken_strength = 0; | |
+ | |
+ int windows_style_sharpening_strength = 0; | |
+ float gamma_correction_value = 1; | |
+ float gamma_correction_lt = 0; | |
+ | |
+ FT_Int brightness_value = 0.0; | |
+ FT_Int contrast_value = 0.0; | |
+ | |
+ FT_Int snapping_sliding_scale_value = 0; | |
+ | |
+ FT_Int global_embolden_x_value = 0; | |
+ FT_Int global_embolden_y_value = 0; | |
+ | |
+ FT_Int bold_embolden_x_value = 0; | |
+ FT_Int bold_embolden_y_value = 0; | |
+ | |
+ FT_Byte chromeos_cutoff; | |
+ double chromeos_gamma_value; | |
+ | |
+ float embolden_value = 0.0; | |
+ FT_Bool autohinted = FALSE; | |
+ FT_Bool use_various_tweaks = FALSE; | |
+ FT_Pos cur_width = infinality_cur_width; | |
+ | |
+ const FT_Int MIN_PPEM = 1; | |
+ /*const FT_Int MAX_PPEM = 100; */ | |
+ | |
+ FT_Bool use_known_settings_on_selected_fonts; | |
+ | |
+ if ( slot->face && | |
+ slot->face->size && | |
+ slot->face->size->metrics.x_ppem ) | |
+ ppem = slot->face->size->metrics.x_ppem; | |
+ else | |
+ ppem = 0; | |
+ | |
+ if ( cur_width ) | |
+ { | |
+ autohinted = TRUE; | |
+ } | |
+ if( ftinf ){ | |
+ const float *f=ftinf->gamma_correction; | |
+ | |
+ use_known_settings_on_selected_fonts=ftinf->use_known_settings_on_selected_fonts; | |
+ use_various_tweaks=ftinf->use_various_tweaks; | |
+ snapping_sliding_scale_value=ftinf->stem_snapping_sliding_scale; | |
+ | |
+ alignment_strength=ftinf->stem_alignment_strength; | |
+ if ( snapping_sliding_scale_value != 0 ) | |
+ alignment_strength = sliding_scale(10, snapping_sliding_scale_value, alignment_strength, 100, ppem); | |
+ | |
+ fitting_strength=ftinf->stem_fitting_strength; | |
+ if ( snapping_sliding_scale_value != 0 ) | |
+ fitting_strength = sliding_scale(10, snapping_sliding_scale_value, fitting_strength, 100, ppem); | |
+ | |
+ chromeos_style_sharpening_strength=ftinf->chromeos_style_sharpening_strength; | |
+ | |
+ if ( ppem > 10 ) | |
+ chromeos_style_sharpening_strength = | |
+ ( chromeos_style_sharpening_strength * ppem ) / 10; | |
+ | |
+ if ( chromeos_style_sharpening_strength > 100 ) | |
+ chromeos_style_sharpening_strength = 100; | |
+ | |
+ brightness_value=ftinf->brightness; | |
+ contrast_value=ftinf->contrast; | |
+ | |
+ windows_style_sharpening_strength=ftinf->windows_style_sharpening_strength; | |
+ | |
+ /* Decrease effect slightly to have a more linear increase in sharpness */ | |
+ windows_style_sharpening_strength = | |
+ ( ( windows_style_sharpening_strength | |
+ * windows_style_sharpening_strength ) / 100 | |
+ + windows_style_sharpening_strength ) / 2; | |
+ gamma_correction_lt = f[0]; | |
+ gamma_correction_value = f[1] / 100.0f; | |
+ | |
+ fringe_filter_strength=ftinf->fringe_filter_strength; | |
+ grayscale_filter_strength=ftinf->grayscale_filter_strength; | |
+ | |
+ autohint_horizontal_stem_darken_strength=ftinf->autohint_horizontal_stem_darken_strength; | |
+ autohint_vertical_stem_darken_strength=ftinf->autohint_vertical_stem_darken_strength; | |
+ | |
+ global_embolden_x_value=ftinf->global_embolden_x_value; | |
+ global_embolden_y_value=ftinf->global_embolden_y_value; | |
+ | |
+ bold_embolden_x_value=ftinf->bold_embolden_x_value; | |
+ bold_embolden_y_value=ftinf->bold_embolden_y_value; | |
+ } else { | |
+ use_known_settings_on_selected_fonts=FALSE; | |
+ } | |
+ | |
+ /* set gamma value to 1 if out of range */ | |
+ if ( slot->face && | |
+ slot->face->size && | |
+ slot->face->size->metrics.x_ppem ) | |
+ { | |
+ if ( slot->face->size->metrics.x_ppem >= gamma_correction_lt ) | |
+ gamma_correction_value = 1; | |
+ } | |
+ else | |
+ gamma_correction_value = 1; | |
+ | |
+ if( use_various_tweaks && | |
+ slot->face && | |
+ slot->face->style_name ) | |
+ { | |
+ /* needs to also check for artifical italics */ | |
+ if ( strcasestr(slot->face->style_name, "Italic" ) || | |
+ strcasestr(slot->face->style_name, "Oblique" ) ) | |
+ { | |
+ windows_style_sharpening_strength = 0; | |
+ chromeos_style_sharpening_strength = 0; | |
+ } | |
+ } | |
+ | |
+ /*if (fitting_strength == 100) scale_value = 1.1;*/ | |
+ | |
+#endif | |
+ | |
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ | |
+ FT_Int lcd_extra = 0; | |
+ FT_LcdFiveTapFilter lcd_weights = { 0 }; | |
+ FT_Bool have_custom_weight = FALSE; | |
+ FT_Bitmap_LcdFilterFunc lcd_filter_func = NULL; | |
+ | |
+ | |
+ if ( slot->face ) | |
+ { | |
+ FT_Char i; | |
+ | |
+ | |
+ for ( i = 0; i < FT_LCD_FILTER_FIVE_TAPS; i++ ) | |
+ if ( slot->face->internal->lcd_weights[i] != 0 ) | |
+ { | |
+ have_custom_weight = TRUE; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ /* | |
+ * The LCD filter can be set library-wide and per-face. Face overrides | |
+ * library. If the face filter weights are all zero (the default), it | |
+ * means that the library default should be used. | |
+ */ | |
+ if ( have_custom_weight ) | |
+ { | |
+ /* | |
+ * A per-font filter is set. It always uses the default 5-tap | |
+ * in-place FIR filter that needs 2 extra pixels. | |
+ */ | |
+ ft_memcpy( lcd_weights, | |
+ slot->face->internal->lcd_weights, | |
+ FT_LCD_FILTER_FIVE_TAPS ); | |
+ lcd_filter_func = ft_lcd_filter_fir; | |
+ lcd_extra = 2; | |
+ } | |
+ else | |
+ { | |
+ /* | |
+ * The face's lcd_weights is {0, 0, 0, 0, 0}, meaning `use library | |
+ * default'. If the library is set to use no LCD filtering | |
+ * (lcd_filter_func == NULL), `lcd_filter_func' here is also set to | |
+ * NULL and the tests further below pass over the filtering process. | |
+ */ | |
+ ft_memcpy( lcd_weights, | |
+ slot->library->lcd_weights, | |
+ FT_LCD_FILTER_FIVE_TAPS ); | |
+ lcd_filter_func = slot->library->lcd_filter_func; | |
+ lcd_extra = slot->library->lcd_extra; | |
+ } | |
+ | |
+#endif /*FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
/* check glyph image format */ | |
if ( slot->format != render->glyph_format ) | |
@@ -446,15 +2541,134 @@ | |
} | |
/* check mode */ | |
- if ( mode != FT_RENDER_MODE_NORMAL && | |
- mode != FT_RENDER_MODE_LIGHT && | |
- mode != FT_RENDER_MODE_LCD && | |
- mode != FT_RENDER_MODE_LCD_V ) | |
+ if ( mode != required_mode ) | |
{ | |
error = FT_THROW( Cannot_Render_Glyph ); | |
goto Exit; | |
} | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+RERENDER: | |
+ if ( align_called == 1 ) | |
+ { | |
+ scaleMat.xx = FT_FixedFromFloat(scale_value); | |
+ scaleMat.xy = 0; | |
+ scaleMat.yx = 0; | |
+ scaleMat.yy = ( 1 << 16 ); | |
+ | |
+ FT_Outline_Copy(outline_orig, outline); | |
+ | |
+ if ( scale_value != 1.0 ) | |
+ FT_Outline_Transform( outline, &scaleMat ); | |
+ | |
+ FT_Outline_Translate( outline, translate_value, 0 ); | |
+ | |
+ FT_Outline_EmboldenXY( outline, embolden_value, 0 ); | |
+ } | |
+ else | |
+ { | |
+#endif | |
+ outline = &slot->outline; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ /* Need to get this PRIOR to embolden, otherwise bad things happen */ | |
+ FT_Outline_Get_CBox( outline, &cbox ); | |
+ | |
+ /* Various hacks that need to be turned into a new rule set */ | |
+ /*if ( !autohinted | |
+ && use_known_settings_on_selected_fonts | |
+ && mode == FT_RENDER_MODE_LCD | |
+ && slot->face->family_name | |
+ && slot->face->style_name | |
+ && ( strcasestr(slot->face->family_name, "Courier New" ) | |
+ && ( strcasestr(slot->face->style_name, "Regular" ) | |
+ || strcasestr(slot->face->style_name, "Italic" ) ) ) ) | |
+ FT_Outline_Embolden( outline, 24 );*/ | |
+ | |
+ if ( slot->face ) | |
+ { | |
+ if ( !autohinted && | |
+ use_known_settings_on_selected_fonts && | |
+ mode == FT_RENDER_MODE_LCD && | |
+ slot->face->family_name && | |
+ slot->face->style_name && | |
+ strcasestr( slot->face->family_name, "Times New Roman" ) && | |
+ strcasestr( slot->face->style_name, "Italic" ) ) | |
+ FT_Outline_EmboldenXY( outline, 12, 0 ); | |
+ | |
+ if ( use_known_settings_on_selected_fonts && | |
+ autohinted && | |
+ mode == FT_RENDER_MODE_LCD && | |
+ slot->face->family_name && | |
+ slot->face->style_name && | |
+ strcasestr(slot->face->family_name, "FreeSerif" ) && | |
+ strcasestr(slot->face->style_name, "Italic" ) ) | |
+ FT_Outline_EmboldenXY( outline, 8, 0 ); | |
+ | |
+ if ( global_embolden_x_value != 0 || global_embolden_y_value != 0 ) | |
+ FT_Outline_EmboldenXY( outline, | |
+ global_embolden_x_value, | |
+ global_embolden_y_value ); | |
+ | |
+ if ( ( bold_embolden_x_value != 0 || bold_embolden_y_value != 0 ) && | |
+ ( slot->face->style_name && | |
+ ( strcasestr(slot->face->style_name, "Bold" ) || | |
+ strcasestr(slot->face->style_name, "Black" ) || | |
+ ( slot->face->style_flags && | |
+ slot->face->style_flags & FT_STYLE_FLAG_BOLD ) ) ) ) | |
+ FT_Outline_EmboldenXY( outline, | |
+ bold_embolden_x_value, | |
+ bold_embolden_y_value ); | |
+ } | |
+ | |
+ FT_Outline_Copy( outline, outline_orig ); | |
+ } | |
+ | |
+ /* translate the outline to the new origin if needed */ | |
+ if ( align_called == 0 ) | |
+ { | |
+ FT_Pos enlarge_cbox = 0; | |
+ | |
+ /* enlarge for grayscale rendering */ | |
+ if ( mode == FT_RENDER_MODE_NORMAL ) | |
+ enlarge_cbox = 64; | |
+ | |
+ if ( origin ) | |
+ { | |
+ FT_Outline_Translate( outline, origin->x, origin->y ); | |
+ have_translated_origin = TRUE; | |
+ } | |
+ | |
+ /* compute the control box, and grid fit it */ | |
+ /*FT_Outline_Get_CBox( outline, &cbox );*/ | |
+ | |
+ cbox.xMin = FT_PIX_FLOOR( cbox.xMin - enlarge_cbox ); | |
+ cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); | |
+ cbox.xMax = FT_PIX_CEIL( cbox.xMax + enlarge_cbox ); | |
+ cbox.yMax = FT_PIX_CEIL( cbox.yMax ); | |
+#else | |
+ if ( origin ) | |
+ { | |
+ FT_Outline_Translate( outline, origin->x, origin->y ); | |
+ have_translated_origin = TRUE; | |
+ } | |
+ | |
+ /* compute the control box, and grid fit it */ | |
+ FT_Outline_Get_CBox( outline, &cbox ); | |
+ | |
+ cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); | |
+ cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); | |
+ cbox.xMax = FT_PIX_CEIL( cbox.xMax ); | |
+ cbox.yMax = FT_PIX_CEIL( cbox.yMax ); | |
+#endif | |
+ | |
+ width = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6; | |
+ height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6; | |
+ | |
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ width_org = width; | |
+ height_org = height; | |
+#endif | |
+ | |
/* release old bitmap buffer */ | |
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | |
{ | |
@@ -462,109 +2676,427 @@ | |
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | |
} | |
- if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) | |
+ /* allocate new one */ | |
+ pitch = width; | |
+ if ( hmul ) | |
{ | |
- error = FT_THROW( Raster_Overflow ); | |
- goto Exit; | |
+ width = width * 3; | |
+ pitch = FT_PAD_CEIL( width, 4 ); | |
} | |
- if ( !bitmap->rows || !bitmap->pitch ) | |
- goto Exit; | |
+ if ( vmul ) | |
+ height *= 3; | |
- /* allocate new one */ | |
- if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) | |
- goto Exit; | |
+ x_shift = cbox.xMin; | |
+ y_shift = cbox.yMin; | |
+ x_left = cbox.xMin >> 6; | |
+ y_top = cbox.yMax >> 6; | |
- slot->internal->flags |= FT_GLYPH_OWN_BITMAP; | |
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ if ( lcd_filter_func ) | |
+ { | |
+ if ( hmul ) | |
+ { | |
+ x_shift -= 64 * ( lcd_extra >> 1 ); | |
+ x_left -= lcd_extra >> 1; | |
+ width += 3 * lcd_extra; | |
+ pitch = FT_PAD_CEIL( width, 4 ); | |
+ } | |
- x_shift = 64 * -slot->bitmap_left; | |
- y_shift = 64 * -slot->bitmap_top; | |
- if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) | |
- y_shift += 64 * (FT_Int)bitmap->rows / 3; | |
- else | |
- y_shift += 64 * (FT_Int)bitmap->rows; | |
+ if ( vmul ) | |
+ { | |
+ y_shift -= 64 * ( lcd_extra >> 1 ); | |
+ y_top += lcd_extra >> 1; | |
+ height += 3 * lcd_extra; | |
+ } | |
+ } | |
+#endif | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ } | |
+#endif | |
- if ( origin ) | |
+ | |
+ /* Required check is (pitch * height < FT_ULONG_MAX), */ | |
+ /* but we care realistic cases only. Always pitch <= width. */ | |
+ if ( width > 0x7FFF || height > 0x7FFF ) | |
{ | |
- x_shift += origin->x; | |
- y_shift += origin->y; | |
+ FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", | |
+ width, height )); | |
+ error = FT_THROW( Raster_Overflow ); | |
+ goto Exit; | |
} | |
- /* translate outline to render it into the bitmap */ | |
- if ( x_shift || y_shift ) | |
- FT_Outline_Translate( outline, x_shift, y_shift ); | |
+ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; | |
+ bitmap->num_grays = 256; | |
+ bitmap->width = (unsigned int)width; | |
+ bitmap->rows = (unsigned int)height; | |
+ bitmap->pitch = pitch; | |
- if ( mode == FT_RENDER_MODE_NORMAL || | |
- mode == FT_RENDER_MODE_LIGHT ) | |
+ /* translate outline to render it into the bitmap */ | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( align_called == 0 ) | |
{ | |
- if ( outline->flags & FT_OUTLINE_OVERLAP ) | |
- error = ft_smooth_raster_overlap( render, outline, bitmap ); | |
- else | |
+#endif | |
+ FT_Outline_Translate( outline, -x_shift, -y_shift ); | |
+ have_outline_shifted = TRUE; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ } | |
+#endif | |
+ /* release old bitmap buffer */ | |
+ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | |
{ | |
- FT_Raster_Params params; | |
+ FT_FREE( bitmap->buffer ); | |
+ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | |
+ } | |
+ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) ) | |
+ goto Exit; | |
+ else | |
+ have_buffer = TRUE; | |
+ slot->internal->flags |= FT_GLYPH_OWN_BITMAP; | |
+ | |
+ /* set up parameters */ | |
params.target = bitmap; | |
params.source = outline; | |
params.flags = FT_RASTER_FLAG_AA; | |
- error = render->raster_render( render->raster, ¶ms ); | |
- } | |
- } | |
- else | |
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
+ | |
+ /* implode outline if needed */ | |
{ | |
- if ( mode == FT_RENDER_MODE_LCD ) | |
- error = ft_smooth_raster_lcd ( render, outline, bitmap ); | |
- else if ( mode == FT_RENDER_MODE_LCD_V ) | |
- error = ft_smooth_raster_lcdv( render, outline, bitmap ); | |
+ FT_Vector* points = outline->points; | |
+ FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); | |
+ FT_Vector* vec; | |
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | |
- /* finally apply filtering */ | |
+ if ( hmul ) | |
+ for ( vec = points; vec < points_end; vec++ ) | |
+ vec->x *= 3; | |
+ | |
+ if ( vmul ) | |
+ for ( vec = points; vec < points_end; vec++ ) | |
+ vec->y *= 3; | |
+ } | |
+ | |
+ /* render outline into the bitmap */ | |
+ error = render->raster_render( render->raster, ¶ms ); | |
+ | |
+ /* deflate outline if needed */ | |
{ | |
- FT_Byte* lcd_weights; | |
- FT_Bitmap_LcdFilterFunc lcd_filter_func; | |
+ FT_Vector* points = outline->points; | |
+ FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); | |
+ FT_Vector* vec; | |
+ | |
+ | |
+ if ( hmul ) | |
+ for ( vec = points; vec < points_end; vec++ ) | |
+ vec->x /= 3; | |
+ | |
+ if ( vmul ) | |
+ for ( vec = points; vec < points_end; vec++ ) | |
+ vec->y /= 3; | |
+ } | |
+ | |
+ if ( error ) | |
+ goto Exit; | |
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET | |
+ if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM ) | |
+ { | |
+ if ( align_called == 0 && cur_width / ppem < 10 && | |
+ ( alignment_strength > 0 || fitting_strength > 0 ) ) | |
+ _lcd_stem_align ( bitmap, | |
+ mode, | |
+ slot, | |
+ &translate_value, | |
+ &scale_value, | |
+ alignment_strength, | |
+ fitting_strength, | |
+ &embolden_value ); | |
- /* Per-face LCD filtering takes priority if set up. */ | |
- if ( slot->face && slot->face->internal->lcd_filter_func ) | |
+ if ( align_called == 0 && | |
+ ( translate_value != 0 || scale_value != 1.0 ) ) | |
{ | |
- lcd_weights = slot->face->internal->lcd_weights; | |
- lcd_filter_func = slot->face->internal->lcd_filter_func; | |
+ align_called = 1; | |
+ goto RERENDER; | |
} | |
- else | |
+ | |
+ if ( mode == FT_RENDER_MODE_LCD ) | |
{ | |
- lcd_weights = slot->library->lcd_weights; | |
- lcd_filter_func = slot->library->lcd_filter_func; | |
+ | |
+ if ( fringe_filter_strength > 0 /*&& autohinted*/ ) | |
+ _ft_lcd_fringe_filter( bitmap, | |
+ mode, | |
+ fringe_filter_strength, | |
+ slot->library ); | |
+ | |
+ /*if ( autohinted) | |
+ _ft_lcd_stem_end_filter( bitmap, mode, 100, slot->library );*/ | |
+ | |
+ if ( gamma_correction_lt > 0 && gamma_correction_value != 1.0 ) | |
+ _ft_lcd_gamma_correction_correction( bitmap, | |
+ mode, | |
+ slot, | |
+ gamma_correction_lt, | |
+ gamma_correction_value ); | |
+ | |
+ chromeos_cutoff = (FT_Byte)( 0.5 * 255.0 ) | |
+ * ( chromeos_style_sharpening_strength / 100.0 ); | |
+ chromeos_gamma_value = 1; | |
+ | |
+ if ( chromeos_style_sharpening_strength > 0 ) | |
+ _ft_lcd_chromeos_sharpen( bitmap, | |
+ mode, | |
+ chromeos_cutoff, | |
+ chromeos_gamma_value ); | |
+ | |
+ if ( ppem > 8 ) | |
+ if ( windows_style_sharpening_strength > 0 ) | |
+ _ft_lcd_windows_sharpen( bitmap, | |
+ mode, | |
+ windows_style_sharpening_strength, | |
+ slot->library ); | |
+ | |
+ if ( autohinted && | |
+ ( cur_width * 100 ) / 64 | |
+ > autohint_horizontal_stem_darken_strength && | |
+ autohint_horizontal_stem_darken_strength != 0 ) | |
+ autohint_horizontal_stem_darken_strength = ( cur_width * 100 ) / 64; | |
+ | |
+ if ( autohint_horizontal_stem_darken_strength > 100) | |
+ autohint_horizontal_stem_darken_strength = 100; | |
+ | |
+ /* only do on autohinted fonts */ | |
+ /* Necessary to do on some non-thin fonts, which is why it is outside */ | |
+ /* of the below conditional */ | |
+ if ( autohint_horizontal_stem_darken_strength > 0 && autohinted ) | |
+ _ft_lcd_darken_x ( bitmap, | |
+ mode, | |
+ autohint_horizontal_stem_darken_strength, | |
+ slot->library ); | |
+ | |
+ /* Enhance thin fonts */ | |
+ if ( autohinted ) | |
+ { | |
+ /* if forcibly set use that, otherwise make a good estimate */ | |
+ float contrast, brightness; | |
+ ftinf_get_bc( slot->face->family_name, ppem, &brightness, &contrast); | |
+ if ( slot->face && !_ft_bitmap_bc ( bitmap, brightness, contrast ) ) | |
+ { | |
+ FT_Bool is_fixed_name = FALSE; | |
+ | |
+ if ( slot->face->family_name && | |
+ strcasestr(slot->face->family_name, "Mono" ) ) | |
+ is_fixed_name = TRUE; | |
+ | |
+ /* Darken vertical stems */ | |
+ _ft_lcd_darken_y ( bitmap, | |
+ mode, | |
+ autohint_vertical_stem_darken_strength, | |
+ slot->library ); | |
+ | |
+ /* Adjust brightness / contrast automatically based on stem width */ | |
+ if ( cur_width != 0 && cur_width < 30 ) | |
+ cur_width = 30; | |
+ | |
+ if ( cur_width >= 30 && cur_width <= 60 ) | |
+ { | |
+ float ppem_factor = sliding_scale ( 5, 11, 0.0, 1.0, ppem ); | |
+ float brightness_factor = sliding_scale ( 30, 52, -.3, 0.0, | |
+ cur_width ); | |
+ float contrast_factor = sliding_scale ( 30, 52, .45, 0.0, | |
+ cur_width ); | |
+ _ft_bitmap_bc ( bitmap, | |
+ ppem_factor * brightness_factor, | |
+ ppem_factor * contrast_factor ); | |
+ | |
+ /* Only cap variable width thin-stemmed fonts */ | |
+ if ( !FT_IS_FIXED_WIDTH( slot->face ) && !is_fixed_name ) | |
+ _ft_bitmap_cap ( bitmap, | |
+ ( cur_width * 150 ) / 64, | |
+ slot->library ); | |
} | |
+ } | |
+ } | |
+ | |
if ( lcd_filter_func ) | |
- lcd_filter_func( bitmap, lcd_weights ); | |
+ lcd_filter_func( bitmap, mode, lcd_weights ); | |
+ | |
+ if ( grayscale_filter_strength > 0 ) | |
+ _ft_lcd_grayscale_filter( bitmap, | |
+ mode, | |
+ grayscale_filter_strength, | |
+ slot->library ); | |
+ | |
} | |
-#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
+ /* Global values */ | |
+ if ( brightness_value != 0 || contrast_value != 0 ) | |
+ _ft_bitmap_bc ( bitmap, | |
+ (float)brightness_value / 300.0, | |
+ (float)contrast_value / 300.0); | |
+ FT_Outline_Done( slot->library, outline_orig ); | |
} | |
+ else if ( mode == FT_RENDER_MODE_LCD && | |
+ lcd_filter_func ) | |
+ lcd_filter_func( bitmap, mode, lcd_weights ); | |
+#else | |
+ if ( lcd_filter_func ) | |
+ lcd_filter_func( bitmap, mode, lcd_weights ); | |
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ | |
- Exit: | |
- if ( !error ) | |
+#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
+ | |
+ /* render outline into bitmap */ | |
+ error = render->raster_render( render->raster, ¶ms ); | |
+ if ( error ) | |
+ goto Exit; | |
+ | |
+ /* expand it horizontally */ | |
+ if ( hmul ) | |
{ | |
- /* everything is fine; the glyph is now officially a bitmap */ | |
- slot->format = FT_GLYPH_FORMAT_BITMAP; | |
+ FT_Byte* line = bitmap->buffer; | |
+ FT_UInt hh; | |
+ | |
+ | |
+ for ( hh = height_org; hh > 0; hh--, line += pitch ) | |
+ { | |
+ FT_UInt xx; | |
+ FT_Byte* end = line + width; | |
+ | |
+ | |
+ for ( xx = width_org; xx > 0; xx-- ) | |
+ { | |
+ FT_UInt pixel = line[xx-1]; | |
+ | |
+ | |
+ end[-3] = (FT_Byte)pixel; | |
+ end[-2] = (FT_Byte)pixel; | |
+ end[-1] = (FT_Byte)pixel; | |
+ end -= 3; | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* expand it vertically */ | |
+ if ( vmul ) | |
+ { | |
+ FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; | |
+ FT_Byte* write = bitmap->buffer; | |
+ FT_UInt hh; | |
+ | |
+ | |
+ for ( hh = height_org; hh > 0; hh-- ) | |
+ { | |
+ ft_memcpy( write, read, pitch ); | |
+ write += pitch; | |
+ | |
+ ft_memcpy( write, read, pitch ); | |
+ write += pitch; | |
+ | |
+ ft_memcpy( write, read, pitch ); | |
+ write += pitch; | |
+ read += pitch; | |
+ } | |
} | |
- else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | |
+ | |
+#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | |
+ | |
+ /* | |
+ * XXX: on 16bit system, we return an error for huge bitmap | |
+ * to prevent an overflow. | |
+ */ | |
+ if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) | |
+ { | |
+ error = FT_THROW( Invalid_Pixel_Size ); | |
+ goto Exit; | |
+ } | |
+ | |
+ slot->format = FT_GLYPH_FORMAT_BITMAP; | |
+ slot->bitmap_left = (FT_Int)x_left; | |
+ slot->bitmap_top = (FT_Int)y_top; | |
+ | |
+ /* everything is fine; don't deallocate buffer */ | |
+ have_buffer = FALSE; | |
+ | |
+ error = FT_Err_Ok; | |
+ | |
+ Exit: | |
+ if ( have_outline_shifted ) | |
+ FT_Outline_Translate( outline, x_shift, y_shift ); | |
+ if ( have_translated_origin ) | |
+ FT_Outline_Translate( outline, -origin->x, -origin->y ); | |
+ if ( have_buffer ) | |
{ | |
FT_FREE( bitmap->buffer ); | |
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | |
} | |
- if ( x_shift || y_shift ) | |
- FT_Outline_Translate( outline, -x_shift, -y_shift ); | |
+ return error; | |
+ } | |
+ | |
+ | |
+ | |
+ /* convert a slot's glyph image into a horizontal LCD bitmap */ | |
+ static FT_Error | |
+ ft_smooth_render_lcd( FT_Renderer render, | |
+ FT_GlyphSlot slot, | |
+ FT_Render_Mode mode, | |
+ const FT_Vector* origin ) | |
+ { | |
+ FT_Error error; | |
+ | |
+ error = ft_smooth_render_generic( render, slot, mode, origin, | |
+ FT_RENDER_MODE_LCD ); | |
+ if ( !error ) | |
+ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; | |
return error; | |
} | |
+ /* convert a slot's glyph image into a vertical LCD bitmap */ | |
+ static FT_Error | |
+ ft_smooth_render_lcd_v( FT_Renderer render, | |
+ FT_GlyphSlot slot, | |
+ FT_Render_Mode mode, | |
+ const FT_Vector* origin ) | |
+ { | |
+ FT_Error error; | |
+ | |
+ error = ft_smooth_render_generic( render, slot, mode, origin, | |
+ FT_RENDER_MODE_LCD_V ); | |
+ if ( !error ) | |
+ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; | |
+ | |
+ return error; | |
+ } | |
+ | |
+ | |
+ | |
+ /* convert a slot's glyph image into a bitmap */ | |
+ static FT_Error | |
+ ft_smooth_render( FT_Renderer render, | |
+ FT_GlyphSlot slot, | |
+ FT_Render_Mode mode, | |
+ const FT_Vector* origin ) | |
+ { | |
+ switch (mode) { | |
+ case FT_RENDER_MODE_LIGHT: | |
+ case FT_RENDER_MODE_NORMAL: | |
+ return ft_smooth_render_generic( render, slot, mode, origin, | |
+ FT_RENDER_MODE_NORMAL ); | |
+ case FT_RENDER_MODE_LCD: | |
+ return ft_smooth_render_lcd( render, slot, mode, origin); | |
+ case FT_RENDER_MODE_LCD_V: | |
+ return ft_smooth_render_lcd_v( render, slot, mode, origin); | |
+ } | |
+ } | |
+ | |
+ | |
FT_DEFINE_RENDERER( | |
ft_smooth_renderer_class, | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment