diff -Nur freetype-subpixel-enabled/include/freetype/internal/ftobjs.h freetype-work/include/freetype/internal/ftobjs.h --- freetype-subpixel-enabled/include/freetype/internal/ftobjs.h 2011-04-29 18:26:58.218161577 -0500 +++ freetype-work/include/freetype/internal/ftobjs.h 2011-04-29 19:30:01.994364397 -0500 @@ -768,8 +768,20 @@ typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, FT_Render_Mode render_mode, FT_Library library ); + + typedef void (*FT_Bitmap_EmboldenFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + float amount ); + + typedef void (*FT_Bitmap_LcdStemAlignFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + FT_GlyphSlot slot, + FT_Long* translate_value, + float* scale_value + ); + /*************************************************************************/ /* */ /* */ @@ -870,6 +882,8 @@ FT_Int lcd_extra; /* number of extra pixels */ FT_Byte lcd_weights[7]; /* filter weights, if any */ FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ + FT_Bitmap_LcdStemAlignFunc lcd_stem_align_func; + FT_Bitmap_EmboldenFunc lcd_embolden_func; #endif #ifdef FT_CONFIG_OPTION_PIC diff -Nur freetype-subpixel-enabled/configure freetype-work/configure --- freetype-2.4.3.orig/configure 2010-10-03 13:05:26.000000000 -0500 +++ freetype-2.4.3.new/configure 2010-11-14 18:17:36.593491866 -0600 @@ -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 if test "x$GNUMAKE" = x; then diff -Nur freetype-subpixel-enabled/src/autofit/aflatin.c freetype-work/src/autofit/aflatin.c --- freetype-subpixel-enabled/src/autofit/aflatin.c 2011-04-29 18:14:22.730917554 -0500 +++ freetype-work/src/autofit/aflatin.c 2011-04-29 19:30:01.997364572 -0500 @@ -22,6 +22,7 @@ #include "aflatin.h" #include "aferrors.h" +#include "strings.h" #ifdef AF_CONFIG_OPTION_USE_WARPER @@ -388,6 +389,8 @@ *blue_ref = flats[num_flats / 2]; *blue_shoot = rounds[num_rounds / 2]; } +/* LOOKS BETTER TO ME */ +*blue_shoot = *blue_ref; /* there are sometimes problems: if the overshoot position of top */ /* zones is under its reference position, or the opposite for bottom */ @@ -529,6 +532,29 @@ AF_LatinAxis axis; FT_UInt nn; + int checked_adjust_heights_env = 0; + FT_Bool adjust_heights = FALSE; + + if ( checked_adjust_heights_env == 0 ) + { + char *adjust_heights_env = getenv( "INFINALITY_FT_AUTOFIT_ADJUST_HEIGHTS" ); + if ( adjust_heights_env != NULL ) + { + if ( strcasecmp(adjust_heights_env, "default" ) != 0 ) + { + if ( strcasecmp(adjust_heights_env, "true") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "1") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "on") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "yes") == 0) + adjust_heights = TRUE; + } + } + checked_adjust_heights_env = 1; + } + if ( dim == AF_DIMENSION_HORZ ) { @@ -556,21 +582,46 @@ { AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; AF_LatinBlue blue = NULL; - + int threshold = 40; for ( nn = 0; nn < Axis->blue_count; nn++ ) { - if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT + || ( adjust_heights && Axis->blues[nn].flags & AF_LATIN_BLUE_TOP ) + ) { blue = &Axis->blues[nn]; break; } } + if ( adjust_heights + && metrics->root.scaler.face->size->metrics.x_ppem < 15 + && metrics->root.scaler.face->size->metrics.x_ppem > 8 ) + threshold = 52; + + /* NEED TO FIND A WAY TO ADJUST CAPS AND LOWER SEPARATELY */ + /* The below does not work */ + /* if (Axis->blues[nn].flags & AF_LATIN_BLUE_SMALL_TOP ) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 15) + threshold = 22; + else threshold = 40; + break; + } + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_CAPITAL_TOP ) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 15) + threshold = 40; + else threshold = 40; + break; + } + */ + if ( blue ) { FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); - FT_Pos fitted = ( scaled + 40 ) & ~63; + FT_Pos fitted = ( scaled + threshold ) & ~63; if ( scaled != fitted ) @@ -1399,7 +1450,8 @@ if ( dist < 0 ) dist = -dist; - dist = FT_MulFix( dist, scale ); + /* round down to pixels */ + dist = FT_MulFix( dist, scale ) & ~63; if ( dist < best_dist ) { best_dist = dist; @@ -1563,9 +1615,33 @@ FT_Int vertical = ( dim == AF_DIMENSION_VERT ); - if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || - axis->extra_light ) - return width; + int checked_stem_snap_env = 0; + FT_Bool stem_snap_light = FALSE; + + if ( checked_stem_snap_env == 0 ) + { + char *stem_snap_env = getenv( "INFINALITY_FT_AUTOFIT_STEM_SNAP_LIGHT" ); + if ( stem_snap_env != NULL ) + { + if ( strcasecmp(stem_snap_env, "default" ) != 0 ) + { + if ( strcasecmp(stem_snap_env, "true") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "1") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "on") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "yes") == 0) + stem_snap_light = TRUE; + } + } + checked_stem_snap_env = 1; + } + + if ( !stem_snap_light ) + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; if ( dist < 0 ) { @@ -1573,8 +1649,67 @@ sign = 1; } - if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || - ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + if ( stem_snap_light + && ( + ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) + || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) + { + 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 - dist ) < 32 + && axis->widths[0].cur > 52 ) + { + if ( strstr(metrics->root.scaler.face->style_name, "Regular") + || strstr(metrics->root.scaler.face->style_name, "Book") + || strstr(metrics->root.scaler.face->style_name, "Medium") + || strcmp(metrics->root.scaler.face->style_name, "Italic") == 0 + || strcmp(metrics->root.scaler.face->style_name, "Oblique") == 0 ) + { + /* regular weight */ + if ( axis->widths[0].cur < 64 ) dist = 64 ; + else if (axis->widths[0].cur < 88) dist = 64; + else if (axis->widths[0].cur < 160) dist = 128; + else if (axis->widths[0].cur < 240) dist = 190; + else dist = ( dist ) & ~63; + } + else + { + /* bold gets a different threshold */ + if ( axis->widths[0].cur < 64 ) dist = 64 ; + else if (axis->widths[0].cur < 108) dist = 64; + else if (axis->widths[0].cur < 160) dist = 128; + else if (axis->widths[0].cur < 222) dist = 190; + else if (axis->widths[0].cur < 288) dist = 254; + else dist = ( dist + 16 ) & ~63; + } + + /* fix any unusually low values */ + if (dist < ( axis->widths[0].cur & ~63 ) ) + dist = (axis->widths[0].cur & ~63); + + /* fix any unusually high values */ + if (dist > ( ( axis->widths[0].cur + 64 ) & ~63 ) ) + dist = ( ( axis->widths[0].cur + 64 ) & ~63 ); + + if (dist < 64 ) dist = 64 ; + + } + if (dist < 52) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 9 ) + { + /*dist = 64 - (64 - dist) / 2 ;*/ + if (dist < 31) dist = 31; + } + else + dist = 52; + } + + } + else if ( !stem_snap_light && (( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ @@ -1633,7 +1768,7 @@ dist = ( dist + 32 ) & ~63; } } - else + else if (!stem_snap_light) { /* strong hinting process: snap the stem width to integer pixels */ @@ -1642,6 +1777,8 @@ dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); + if ( stem_snap_light ) goto Done_Width; + if ( vertical ) { /* in the case of vertical hinting, always round */ @@ -1726,7 +1863,7 @@ (AF_Edge_Flags)base_edge->flags, (AF_Edge_Flags)stem_edge->flags ); - +/*if (base_edge->pos < 128 )*/ /*************************************************************************/ /*find a condition of the middle of a letter */ stem_edge->pos = base_edge->pos + fitted_width; FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to (%.2f)," @@ -2187,7 +2324,30 @@ { FT_Error error; int dim; + int e_strength = 0; + + int checked_embolden_light_env = 0; + FT_Bool embolden_light = FALSE; + if ( checked_embolden_light_env == 0 ) + { + char *embolden_light_env = getenv( "INFINALITY_FT_AUTOFIT_EMBOLDEN_LIGHT" ); + if ( embolden_light_env != NULL ) + { + if ( strcasecmp(embolden_light_env, "default" ) != 0 ) + { + if ( strcasecmp(embolden_light_env, "true") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "1") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "on") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "yes") == 0) + embolden_light = TRUE; + } + } + checked_embolden_light_env = 1; + } error = af_glyph_hints_reload( hints, outline ); if ( error ) @@ -2235,8 +2395,15 @@ } #endif - if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || - ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ) + { + af_latin_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + + if ( ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { af_latin_hint_edges( hints, (AF_Dimension)dim ); af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); @@ -2246,6 +2413,38 @@ } af_glyph_hints_save( hints, outline ); + /* if the font is particularly thin, embolden it, up to 1 px */ + if ( embolden_light + && metrics->axis->widths[0].cur <= 64 + && !( dim == AF_DIMENSION_VERT ) + && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) + { + if ( metrics->axis->widths[0].cur + / metrics->root.scaler.face->size->metrics.x_ppem < 5 ) + { + /* make the width 1 pixel */ + e_strength = 64 - metrics->axis->widths[0].cur; + /* But don't do low ppems as much */ + if ( metrics->root.scaler.face->size->metrics.x_ppem < 13 ) + e_strength -= 10; + /*( 9 - metrics->root.scaler.face->size->metrics.x_ppem ) * 15;*/ + if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 ) + e_strength -= 10; + } + /* Embolden small fonts on a sliding scale. Better readability. */ + /*if ( e_strength > 0 + && ( strstr(metrics->root.scaler.face->style_name, "Regular") + || strstr(metrics->root.scaler.face->style_name, "Book") + || strstr(metrics->root.scaler.face->style_name, "Light") + || strstr(metrics->root.scaler.face->style_name, "Medium") + || strcmp(metrics->root.scaler.face->style_name, "Italic") == 0 + || strcmp(metrics->root.scaler.face->style_name, "Oblique") == 0 ) )*/ + if ( e_strength > 0 + && ( strcmp(metrics->root.scaler.face->style_name, "Bold") != 0 + || strcmp(metrics->root.scaler.face->style_name, "Black") != 0 ) ) + FT_Outline_Embolden(outline,e_strength); + } + Exit: return error; } diff -Nur freetype-subpixel-enabled/src/autofit/afloader.c freetype-work/src/autofit/afloader.c --- freetype-subpixel-enabled/src/autofit/afloader.c 2011-04-29 18:14:22.731917611 -0500 +++ freetype-work/src/autofit/afloader.c 2011-04-29 19:30:02.074368988 -0500 @@ -190,8 +190,8 @@ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ - - if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) +/* dont hint metrics - temporary until different hinting can be done */ + if ( FALSE && axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; @@ -224,7 +224,8 @@ slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } - else +/* dont hint metrics - temporary until different hinting can be done */ + else if (FALSE) { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; diff -Nur freetype-subpixel-enabled/src/base/ftlcdfil.c freetype-work/src/base/ftlcdfil.c --- freetype-subpixel-enabled/src/base/ftlcdfil.c 2011-04-29 18:14:22.735917840 -0500 +++ freetype-work/src/base/ftlcdfil.c 2011-06-04 18:02:27.781563156 -0500 @@ -21,9 +21,571 @@ #include FT_IMAGE_H #include FT_INTERNAL_OBJECTS_H +#include +#include +#include #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING +int gamma2 ( int val, float value ) { + return 256 * (1.0 - pow((1.0 - (float)val/ 256.0) , 1.0/value)); +} + + + /*************************************************************************/ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + + 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; + } 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_Short zone; /* 1 2 or 3 */ + } Stem; + + + static void + swap_stem ( Stem s1, Stem s2 ) + { + Stem s; + s.center = s1.center; + s.count = s1.count; + s.rcount = s1.rcount; + s.width = s1.width; + s.zone = s1.zone; + + s1.center = s2.center; + s1.count = s2.count; + s1.rcount = s2.rcount; + s1.width = s2.width; + s1.zone = s2.zone; + + s2.center = s1.center; + s2.count = s1.count; + s2.rcount = s1.rcount; + s2.width = s1.width; + s2.zone = s1.zone; + } + + /* Stem alignment for bitmaps; A hack with very nice results */ + /* Ideally this could be implemented on the outline, prior to + * rasterization */ + static void + _lcd_stem_align ( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_GlyphSlot slot, + FT_Long* translate_value, + float* scale_value + + ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + + Stem_Segment segments[height * width / 2]; + Stem_Segment leftmost_segment, rightmost_segment; + Stem stems[3]; /* only look at top 3 for now */ + Stem possible_stems[3]; + Stem leftmost_stem, rightmost_stem; + Stem_Center centers[height * width / 2]; + + FT_Long leftmost_point = width * 256, rightmost_point = 0; + + FT_Long num_segments = 0; + FT_Long num_centers = 0; + + FT_Long stem_centers[width * 256]; + FT_Long stem_widths[width * 256]; + FT_Long last_y[width * 256]; + + FT_UInt h; + FT_ULong valid_stems = 0, valid_possible_stems = 0; + + FT_UInt alignment_strength = 0; + FT_UInt fitting_strength = 0; + + FT_UInt checked_alignment_strength = 0; + FT_UInt checked_fitting_strength = 0; + + float pseudo_gamma_value = 1; + float pseudo_gamma_lt = 0; + FT_UInt checked_pseudo_gamma_value = 0; + + /* Simply return in odd cases where these don't seem to be set */ + if ( !slot->face ) return; + if ( !slot->face->size ) return; + + if ( checked_alignment_strength == 0) + { + char *alignment_strength_env = getenv( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" ); + if ( alignment_strength_env != NULL ) + { + sscanf ( alignment_strength_env, "%d", &alignment_strength ); + if (alignment_strength > 100 ) alignment_strength = 100; + else if (alignment_strength < 0 ) alignment_strength = 0; + } + checked_alignment_strength = 1; + } + + if ( checked_fitting_strength == 0) + { + char *fitting_strength_env = getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" ); + if ( fitting_strength_env != NULL ) + { + sscanf ( fitting_strength_env, "%d", &fitting_strength ); + if (fitting_strength > 100 ) fitting_strength = 100; + else if (fitting_strength < 0 ) fitting_strength = 0; + } + checked_fitting_strength = 1; + } + + if ( checked_pseudo_gamma_value == 0 ) + { + char *pseudo_gamma_value_env = getenv( "INFINALITY_FT_PSEUDO_GAMMA" ); + if ( pseudo_gamma_value_env != NULL ) + { + float f1, f2; + + if ( strcasecmp(pseudo_gamma_value_env, "default" ) != 0) + { + sscanf ( pseudo_gamma_value_env, "%f %f", &f1, &f2 ); + pseudo_gamma_lt = f1; + pseudo_gamma_value = f2 / 100.0; + } + if ( pseudo_gamma_value < .01 ) pseudo_gamma_value = 1.0; + /*if ( pseudo_gamma_lt < 0 ) pseudo_gamma_lt = 100;*/ + } + checked_pseudo_gamma_value = 1; + } + + /* set gamma value to 1 if out of range */ + if ( slot->face->size->metrics.x_ppem >= pseudo_gamma_lt ) + { + pseudo_gamma_value = 1; + } + + if ( mode == FT_RENDER_MODE_LCD ) + { + if (width >= 4 /*&& alignment_type != 0*/ ) + { + FT_Byte* line = bitmap->buffer; + FT_UInt current_value = 0; + FT_UInt xx; + + line = bitmap->buffer; + + for ( xx = 0; xx < width * 256; xx += 1 ) + { + stem_centers[xx] = 0; + stem_widths[xx] = 0; + last_y[xx] = (FT_UInt)bitmap->rows + 1; + } + for ( xx = 0; xx < width * height / 2; xx += 1 ) + { + segments[xx].x1 = 0; + segments[xx].x2 = 0; + segments[xx].y = 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; + + for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch ) + { + /* Calculate various sums and stem widths of glyph */ + for ( xx = 0; xx < width; xx += 1 ) + { + /******* locate stem centers for later processing *********/ + if (current_value == 0 && line[xx] > 0) + { + /* start of stem */ + segments[num_segments].x1 = 256 * xx + (255 - line[xx]); + segments[num_segments].y = h; + } + else if (current_value > 0 && line[xx] == 0) + { + FT_Long scenter, swidth; + segments[num_segments].x2 = 256 * xx + line[xx]; + scenter = (segments[num_segments].x2 + segments[num_segments].x1) / 2; + swidth = segments[num_segments].x2 - segments[num_segments].x1; + + centers[num_centers].x = scenter; + centers[num_centers].y = h; + num_centers++; + + /* if the stem center is new, or was also used in previous line, count it */ + /* Essentially this favors continous stems more than ones with breaks in them */ + if (last_y[scenter] > (FT_UInt)bitmap->rows || last_y[scenter] == h + 1) + stem_centers[scenter] += 1; + + /* remember which line this center was used on last */ + last_y[scenter] = h; + + stem_widths[scenter] += swidth; /* always go with smallest width in order to get rid of horizontal lines */ + + /******* left and rightmost for later calcluations */ + if (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) + { + rightmost_segment.x1 = segments[num_segments].x1; + rightmost_segment.x2 = segments[num_segments].x2; + rightmost_segment.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; + } + + num_segments++; + } + /* else - other conditions - need some error checking here */ + + + current_value = line[xx]; + } + } + + /* initialize */ + for ( xx = 0; xx < 3; xx +=1 ) + { + stems[xx].center = 0; + stems[xx].count = 0; + stems[xx].width = 0; + possible_stems[xx].center = 0; + possible_stems[xx].count = 0; + possible_stems[xx].width = 0; + } + valid_stems = 0; + valid_possible_stems = 0; + + /* PHASE 1: Find the top 3 used stem centers */ + for ( xx = 0; xx < width * 256; xx +=1 ) + { + if ( stem_centers[xx] > stems[0].count && stem_widths[xx] / stem_centers[xx] < (width * 256) / 2 ) + { + stems[0].center = xx; + stems[0].count = stem_centers[xx]; + stems[0].width = stem_widths[xx] / stem_centers[xx]; + } + else if ( stem_centers[xx] > stems[1].count && stem_widths[xx] / stem_centers[xx] < (width * 256) / 2 && xx > stems[0].center + stems[0].width / 2) + { + stems[1].center = xx; + stems[1].count = stem_centers[xx]; + stems[1].width = stem_widths[xx] / stem_centers[xx]; + } + else if ( stem_centers[xx] > stems[2].count && stem_widths[xx] / stem_centers[xx] < (width * 256) / 2 && xx > stems[1].center + stems[1].width / 2 && xx > stems[0].center + stems[0].width / 2) + { + stems[2].center = xx; + stems[2].count = stem_centers[xx]; + stems[2].width = stem_widths[xx]/ stem_centers[xx]; + } + + /* calculate stem extremes */ + if (xx < leftmost_stem.center && stem_centers[xx] > 0) + { + leftmost_stem.center = xx; + leftmost_stem.count = stem_centers[xx]; + leftmost_stem.width = stem_widths[xx] / stem_centers[xx]; + } + if (xx > rightmost_stem.center && stem_centers[xx] > 0) + { + rightmost_stem.center = xx; + rightmost_stem.count = stem_centers[xx]; + rightmost_stem.width = stem_widths[xx] / stem_centers[xx]; + } + } + + if (stems[0].count > 1 && stems[0].width < (width * 256) / 2 ) valid_stems++; else stems[0].center = 0; + if (stems[1].count > 1 && stems[1].width < (width * 256) / 2 ) valid_stems++; else stems[1].center = 0; + if (stems[2].count > 1 && stems[2].width < (width * 256) / 2 ) valid_stems++; else stems[2].center = 0; + + + + /* determine zone */ + for ( xx = 0; xx < 3; xx +=1 ) + { + if ( stems[xx].center < (256 * width) / 3 ) stems[xx].zone = 1; + else if ( stems[xx].center < (2 * 256 * width) / 3 ) stems[xx].zone = 2; + else if ( stems[xx].center < 256 * width ) stems[xx].zone = 3; + } + + FT_Long center, row, matchesup, matchesdown, backwards_i, forwards_i, deltarow = 0; + + /* slope at within which to consider a point part of a stem */ + const FT_UInt slope = 10; + /*look at each detected center point*/ + center = 0; + + + while ( center < num_centers ) + { + /*printf("center %d \n", center);*/ + matchesup=0; + /*check higher adjacent rows*/ + row = centers[center].y + 1; + deltarow = 0; + while ( row < (FT_UInt)bitmap->rows && matchesup == deltarow ) + { + deltarow = row - centers[center].y; + backwards_i = center - 1; + while ( backwards_i >= 0 && matchesup >= 0) + { + if ( (centers[center].x - centers[backwards_i].x) < ( centers[center].y / slope ) + && (centers[center].x - centers[backwards_i].x) > ( -centers[center].y / slope ) ) + { + if (centers[backwards_i].x != stems[0].center ) matchesup++; + else matchesup = -100; /* exit if this matches an existing stem */ + } + backwards_i--; + } + if ( matchesup > deltarow ) matchesup = deltarow; + row++; + } + + matchesdown=0; + /*check lower adjacent rows*/ + row = centers[center].y - 1; + deltarow = 0; + while ( row >= 0 && matchesdown == deltarow ) + { + deltarow = centers[center].y - row; + forwards_i = center + 1; + while ( forwards_i < num_centers ) + { + if ( (centers[center].x - centers[forwards_i].x) < ( centers[center].y / slope ) + && (centers[center].x - centers[forwards_i].x) > ( -centers[center].y / slope ) ) + { + if (centers[forwards_i].x != stems[0].center ) matchesdown++; + else matchesdown = -100; /* exit if this matches an existing stem */ + } + forwards_i++; + } + if ( matchesdown > deltarow ) matchesdown = deltarow; + row--; + } + + /*store and/or replace highest occurrences with 3 or more centers */ + if ( matchesdown + 1 + matchesup > possible_stems[0].count && matchesdown + 1 + matchesup >= 3 ) + { + valid_possible_stems = 1; + possible_stems[0].center = centers[center].x; + possible_stems[0].count = matchesdown + 1 + matchesup; + possible_stems[0].width = centers[center].w; + } + center++; + + } + + /* promote to stem */ + if (valid_stems == 1 && valid_possible_stems >= 1){ + stems[1].center = possible_stems[0].center; + stems[1].count = possible_stems[0].count; + stems[1].width = possible_stems[0].width; + valid_stems++; + } + + if (valid_stems == 3) + { + if (stems[0].center > stems[1].center) + swap_stem ( stems[0], stems[1] ); + if (stems[0].center > stems[2].center) + swap_stem ( stems[0], stems[2] ); + if (stems[1].center > stems[2].center) + swap_stem ( stems[1], stems[2] ); + + /* only look at first and last stem */ + swap_stem ( stems[1], stems[2] ); + valid_stems--; + } + + if (valid_stems == 2) + { + if (stems[0].center > stems[1].center) + swap_stem ( stems[0], stems[1] ); + } + + if (valid_stems >= 1) + { + FT_Int center_offset = 256 + 128; /* set to center of a pixel */ + FT_Int delta; + delta = stems[0].center % (256 * 3) + center_offset; + + *translate_value = ( - (stems[0].center + 64) % (256 * 3) + center_offset )/12; /* works OK */ + + /* Method 2 - In zone 1, Round down if able to */ + if (stems[0].zone == 1) + { + *translate_value = (-stems[0].center % (256 * 3) + center_offset) / 12; + } + /* in zone 2, simple round */ + else if (stems[0].zone == 2) + { + /* Method 1 - simple rounding of the center value */ + delta = stems[0].center % (256 * 3) + center_offset; + if (delta < center_offset ) *translate_value = ( -delta) / 12; /* snap left */ + else *translate_value = (256 * 3 - delta ) / 12; /* snap right */ + } + else /*round up if able to for zone 3*/ + { + *translate_value = (256 * 3 - (stems[0].center % (256 * 3) + center_offset)) / 12; + } + + } + + + /* METHOD 3: if 2 stems is detected, scale distance between in order to land on pixels */ + if ( valid_stems == 2) + { + FT_Long stem_distance, new_distance; + FT_Int delta; + + stem_distance = abs(stems[1].center - stems[0].center); /* assumes main stem is on left */ /* need to fix... maybe */ + + delta = stem_distance % ( 256 * 3 ); + + new_distance = stem_distance - delta; + if (stem_distance < (width - 6) * 256 && stem_distance >= 256*3 ) + { + if (delta < 256 + 96 ) new_distance = stem_distance - delta; + else new_distance = stem_distance + (256 * 3 - delta); + } + + if (stem_distance > 0 && new_distance > 0) + { + /* cap the scale value at a certain range */ + /* 256 * 3 is 1 pixel */ + /* 128 * 3 in either direction should be the max strengh to allow */ + float delta2; + + FT_Int max_strength = (128 * fitting_strength) / 100; + + delta2 = new_distance - (float)stem_distance; + 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 - ((stems[0].center * (float)new_distance) / (float)stem_distance - stems[0].center) / 12; /* (256 * 3 / 64)*/ + } + } + + /* USE THESE TO ALLOW CONTROL OF THE "STRENGTH" OF EACH */ + /* cap the translate value at a certain range */ + FT_Int max_strength = (32 * alignment_strength) / 100; + if (*translate_value < -max_strength) *translate_value = -max_strength; + else if (*translate_value > max_strength) *translate_value = max_strength; + + /* realign glyph under certain conditions */ + if (abs(*translate_value) > 10 && width < 24 && width > 6 * 3 ) + { + FT_Long rpp, lpp, spp; + rpp = (FT_ULong)(*translate_value * 12 + (float)rightmost_point * *scale_value); + lpp = (FT_ULong)(*translate_value * 12 + (float)leftmost_point * *scale_value); + spp = (FT_ULong)(*translate_value * 12 + (float)stems[0].center * *scale_value); + + /* leftmost point passes a pixel boundary AND rightmost point does too AND there is room */ + /* this does seem to work pretty nicely */ + if ( lpp % (256 * 3) > leftmost_point % (256 * 3) + && rpp % (256 * 3) > rightmost_point % (256 * 3) + && lpp > 256*4 + && spp > 256 * 8 && rpp > (width - 5) * 256 + + ) + { + *translate_value -= 64; + } + } + } + + if ( pseudo_gamma_value != 1 ) + { + FT_Byte* line = bitmap->buffer; + float ppem = (float)slot->face->size->metrics.x_ppem; + + 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] = gamma2 ( line[xx], pseudo_gamma_value );*/ + + /* sloped */ + /*line[xx] = gamma2 ( line[xx], pseudo_gamma_value - 5 + * (1-pseudo_gamma_value)/(pseudo_gamma_lt -5) + + ((1-pseudo_gamma_value)/(pseudo_gamma_lt -5)) * ppem );*/ + + /* 1/3-sloped */ + line[xx] = gamma2 ( line[xx], pseudo_gamma_value - 5 + * ((1-pseudo_gamma_value)/(3*(pseudo_gamma_lt -5))) + * + ((1-pseudo_gamma_value)/(3*(pseudo_gamma_lt -5))) * ppem ); + } + } + } + } + } + + + static void + _embolden_bitmap ( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + float amount ) + { + if ( render_mode != FT_RENDER_MODE_LCD ) return; + + FT_Byte* line = bitmap->buffer; + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + + for (height = (FT_UInt)bitmap->rows; height > 0; height--, line += bitmap->pitch ) + { + FT_UInt xx; + + for ( xx = 0; xx < width; xx += 1 ) + { + line[xx] = amount * (float)line[xx]; + if (line[xx] > 255) line[xx] = 255; + } + } + + return; + } + /* define USE_LEGACY to implement the legacy filter */ #define USE_LEGACY @@ -44,7 +606,8 @@ FT_Byte* line = bitmap->buffer; - for ( ; height > 0; height--, line += bitmap->pitch ) + line = bitmap->buffer; + for (height = (FT_UInt)bitmap->rows; height > 0; height--, line += bitmap->pitch ) { FT_UInt fir[5]; FT_UInt val1, xx; @@ -69,6 +632,7 @@ val = line[xx]; + pix = fir[0] + weights[0] * val; fir[0] = fir[1] + weights[1] * val; fir[1] = fir[2] + weights[2] * val; @@ -287,9 +851,50 @@ { 0x00, 0x55, 0x56, 0x55, 0x00 }; /* the values here sum up to a value larger than 256, */ /* providing a cheap gamma correction */ - static const FT_Byte default_filter[5] = + static FT_Byte default_filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 }; + int checked_filter_params_env = 0; + + if ( checked_filter_params_env == 0 ) + { + char *filter_params = getenv( "INFINALITY_FT_FILTER_PARAMS" ); + if ( filter_params != NULL && strcmp(filter_params, "") != 0 ) + { + float f1, f2, f3, f4, f5; + + if ( strcasecmp(filter_params, "default" ) != 0) + { + int args_assigned = 0; + args_assigned = sscanf ( filter_params, "%f %f %f %f %f", &f1, &f2, &f3, &f4, &f5 ); + + if ( args_assigned == 5 ) + { + if ( f1 + f2 + f3 + f4 + f5 > 5 ) + { + /* Assume we were given integers instead of floats */ + /* 0 to 100 */ + default_filter[0] = (FT_Byte) (f1 * 2.55f + 0.5f); + default_filter[1] = (FT_Byte) (f2 * 2.55f + 0.5f); + default_filter[2] = (FT_Byte) (f3 * 2.55f + 0.5f); + default_filter[3] = (FT_Byte) (f4 * 2.55f + 0.5f); + default_filter[4] = (FT_Byte) (f5 * 2.55f + 0.5f); + } + else + { + /* Assume we were given floating point values */ + /* 0 to 1.0 */ + default_filter[0] = (FT_Byte) (f1 * 255.0f + 0.5f); + default_filter[1] = (FT_Byte) (f2 * 255.0f + 0.5f); + default_filter[2] = (FT_Byte) (f3 * 255.0f + 0.5f); + default_filter[3] = (FT_Byte) (f4 * 255.0f + 0.5f); + default_filter[4] = (FT_Byte) (f5 * 255.0f + 0.5f); + } + } + } + } + checked_filter_params_env = 1; + } if ( !library ) return FT_Err_Invalid_Argument; @@ -304,17 +909,20 @@ case FT_LCD_FILTER_DEFAULT: #if defined( FT_FORCE_LEGACY_LCD_FILTER ) + library->lcd_stem_align_func = _lcd_stem_align; library->lcd_filter_func = _ft_lcd_filter_legacy; library->lcd_extra = 0; #elif defined( FT_FORCE_LIGHT_LCD_FILTER ) + library->lcd_stem_align_func = _lcd_stem_align; ft_memcpy( library->lcd_weights, light_filter, 5 ); library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; #else + library->lcd_stem_align_func = _lcd_stem_align; ft_memcpy( library->lcd_weights, default_filter, 5 ); library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; @@ -325,6 +933,8 @@ case FT_LCD_FILTER_LIGHT: ft_memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_stem_align_func = _lcd_stem_align; + library->lcd_embolden_func = _embolden_bitmap; library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; break; @@ -332,6 +942,7 @@ #ifdef USE_LEGACY case FT_LCD_FILTER_LEGACY: + library->lcd_stem_align_func = _lcd_stem_align; library->lcd_filter_func = _ft_lcd_filter_legacy; library->lcd_extra = 0; break; diff -Nur freetype-subpixel-enabled/src/base/ftobjs.c freetype-work/src/base/ftobjs.c --- freetype-subpixel-enabled/src/base/ftobjs.c 2011-04-29 18:14:22.737917954 -0500 +++ freetype-work/src/base/ftobjs.c 2011-04-29 19:30:02.082369447 -0500 @@ -562,6 +562,65 @@ FT_Module hinter; TT_Face ttface = (TT_Face)face; + TT_Face face2=(TT_Face)face; + int checked_auto_autohint_env; + FT_Bool auto_autohint = FALSE; + + if ( !checked_auto_autohint_env ) + { + char *auto_autohint_env = getenv( "INFINALITY_FT_AUTO_AUTOHINT" ); + if ( auto_autohint_env != NULL ) + { + if ( strcasecmp(auto_autohint_env, "default" ) != 0 ) + { + if ( strcasecmp(auto_autohint_env, "true") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "1") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "on") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "yes") == 0) auto_autohint = TRUE; + } + } + checked_auto_autohint_env = 1; + } + + int checked_force_slight_hinting_env; + FT_Bool force_slight_hinting = FALSE; + + if ( !checked_force_slight_hinting_env ) + { + char *force_slight_hinting_env = getenv( "INFINALITY_FT_AUTOFIT_FORCE_SLIGHT_HINTING" ); + if ( force_slight_hinting_env != NULL ) + { + if ( strcasecmp(force_slight_hinting_env, "default" ) != 0 ) + { + if ( strcasecmp(force_slight_hinting_env, "true") == 0) force_slight_hinting = TRUE; + else if ( strcasecmp(force_slight_hinting_env, "1") == 0) force_slight_hinting = TRUE; + else if ( strcasecmp(force_slight_hinting_env, "on") == 0) force_slight_hinting = TRUE; + else if ( strcasecmp(force_slight_hinting_env, "yes") == 0) force_slight_hinting = TRUE; + } + } + checked_auto_autohint_env = 1; + } + +/*printf("%d,%d ", load_flags, FT_LOAD_TARGET_NORMAL); +10000001000101000 +0#define FT_LOAD_DEFAULT 0x0 +0#define FT_LOAD_NO_SCALE 0x1 +0#define FT_LOAD_NO_HINTING 0x2 +1#define FT_LOAD_RENDER 0x4 +0#define FT_LOAD_NO_BITMAP 0x8 +1#define FT_LOAD_VERTICAL_LAYOUT 0x10 +0#define FT_LOAD_FORCE_AUTOHINT 0x20 +0#define FT_LOAD_CROP_BITMAP 0x40 +0#define FT_LOAD_PEDANTIC 0x80 +1#define FT_LOAD_ADVANCE_ONLY 0x100 +0#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +0#define FT_LOAD_NO_RECURSE 0x400 +0#define FT_LOAD_IGNORE_TRANSFORM 0x800 +0#define FT_LOAD_MONOCHROME 0x1000 +0#define FT_LOAD_LINEAR_DESIGN 0x2000 +0#define FT_LOAD_SBITS_ONLY 0x4000 +1#define FT_LOAD_NO_AUTOHINT 0x8000U +*/ if ( !face || !face->size || !face->glyph ) return FT_Err_Invalid_Face_Handle; @@ -642,6 +701,20 @@ { FT_AutoHinter_Service hinting; + if ( force_slight_hinting ) + { + load_flags = 66088; + /* attempt to force slight hinting here, but doesn't work */ + /* the above hack does though, until I can figure out the below */ + + /*load_flags &= ~FT_RENDER_MODE_NORMAL; + load_flags &= ~FT_LOAD_TARGET_NORMAL; + load_flags &= ~FT_LOAD_NO_AUTOHINT; + load_flags |= FT_RENDER_MODE_LIGHT; + load_flags |= FT_LOAD_TARGET_LIGHT; + load_flags |= FT_LOAD_FORCE_AUTOHINT;*/ + /*printf("%d ", load_flags);*/ + } /* try to load embedded bitmaps first if available */ /* */ @@ -687,6 +760,12 @@ if ( error ) goto Exit; + /*if ( auto_autohint ) + { + load_flags = 197128; + printf("%d ", load_flags); + }*/ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) { /* check that the loaded outline is correct */ diff -Nur freetype-subpixel-enabled/src/base/ftoutln.c freetype-work/src/base/ftoutln.c --- freetype-subpixel-enabled/src/base/ftoutln.c 2011-04-29 18:14:22.737917954 -0500 +++ freetype-work/src/base/ftoutln.c 2011-04-29 19:30:02.084369562 -0500 @@ -888,6 +888,28 @@ FT_Int c, n, first; FT_Int orientation; + int checked_enhanced_embolden_env = 0; + FT_Bool enhanced_embolden = FALSE; + + if ( checked_enhanced_embolden_env == 0 ) + { + char *enhanced_embolden_env = getenv( "INFINALITY_FT_ENHANCED_EMBOLDEN" ); + if ( enhanced_embolden_env != NULL ) + { + if ( strcasecmp(enhanced_embolden_env, "default" ) != 0 ) + { + if ( strcasecmp(enhanced_embolden_env, "true") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "1") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "on") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "yes") == 0) + enhanced_embolden = TRUE; + } + } + checked_enhanced_embolden_env = 1; + } if ( !outline ) return FT_Err_Invalid_Argument; @@ -957,7 +979,8 @@ } outline->points[n].x = v_cur.x + strength + in.x; - outline->points[n].y = v_cur.y + strength + in.y; + if ( !enhanced_embolden ) + outline->points[n].y = v_cur.y + strength + in.y; v_prev = v_cur; v_cur = v_next; diff -Nur freetype-subpixel-enabled/src/base/ftsynth.c freetype-work/src/base/ftsynth.c --- freetype-subpixel-enabled/src/base/ftsynth.c 2011-04-29 18:14:22.738918012 -0500 +++ freetype-work/src/base/ftsynth.c 2011-04-29 19:30:02.085369618 -0500 @@ -88,9 +88,28 @@ FT_Error error; FT_Pos xstr, ystr; + int checked_enhanced_embolden_env = 0; + FT_Bool enhanced_embolden = FALSE; + + if ( checked_enhanced_embolden_env == 0 ) + { + char *enhanced_embolden_env = getenv( "INFINALITY_FT_EMBOLDEN_MAINTAIN_WIDTH" ); + if ( enhanced_embolden_env != NULL ) + { + if ( strcasecmp(enhanced_embolden_env, "default" ) != 0 ) + { + if ( strcasecmp(enhanced_embolden_env, "true") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "1") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "on") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "yes") == 0) enhanced_embolden = TRUE; + } + } + checked_enhanced_embolden_env = 1; + } + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && - slot->format != FT_GLYPH_FORMAT_BITMAP ) + slot->format != FT_GLYPH_FORMAT_BITMAP ) return; /* some reasonable strength */ @@ -108,7 +127,7 @@ xstr = xstr * 2; ystr = xstr; } - else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ + else if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) { /* round to full pixels */ xstr &= ~63; @@ -146,7 +165,8 @@ slot->metrics.width += xstr; slot->metrics.height += ystr; slot->metrics.horiBearingY += ystr; - slot->metrics.horiAdvance += xstr; + /* Don't add any horiAdvance - Personal preference */ + if ( !enhanced_embolden ) slot->metrics.horiAdvance += xstr; slot->metrics.vertBearingX -= xstr / 2; slot->metrics.vertBearingY += ystr; slot->metrics.vertAdvance += ystr; diff -Nur freetype-subpixel-enabled/src/smooth/ftsmooth.c freetype-work/src/smooth/ftsmooth.c --- freetype-subpixel-enabled/src/smooth/ftsmooth.c 2011-04-29 18:14:22.778920301 -0500 +++ freetype-work/src/smooth/ftsmooth.c 2011-06-04 17:41:10.380005083 -0500 @@ -25,6 +25,7 @@ #include "ftspic.h" #include "ftsmerrs.h" +#include /* initialize renderer -- init its raster */ @@ -94,6 +95,55 @@ } +static FT_Fixed FT_FixedFromFloat(float f) +{ + short value = f; + unsigned short fract = (f - value) * 0xFFFF; + return (FT_Fixed)((long)value << 16 | (unsigned long)fract); +} + + + /* soften the sub-pixel anti-aliasing and sharpen */ + static void + _ft_subpixel_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_Byte* line = bitmap->buffer; + for ( ; height > 0; height--, line += bitmap->pitch ) + { + FT_UInt xx; + for ( xx = 0; xx < width; xx++ ) + { + line[xx] = gamma_ramp[line[xx]]; + } + } + } + } + /* convert a slot's glyph image into a bitmap */ static FT_Error ft_smooth_render_generic( FT_Renderer render, @@ -104,6 +154,7 @@ { FT_Error error; FT_Outline* outline = NULL; + FT_Outline* outline_orig = NULL; FT_BBox cbox; FT_UInt width, height, pitch; #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING @@ -111,9 +162,27 @@ FT_Int hmul = mode == FT_RENDER_MODE_LCD; FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; FT_Pos x_shift, y_shift, x_left, y_top; + FT_Matrix scaleMat; - FT_Raster_Params params; + FT_Long translate_value = 0; + float scale_value = 1.0; + FT_Int align_called = 0; + FT_Raster_Params params; + FT_UInt chromeos_style_sharpening_strength = 0; + FT_UInt checked_chromeos_style_sharpening_strength = 0; + + if ( checked_chromeos_style_sharpening_strength == 0) + { + char *chromeos_style_sharpening_strength_env = getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" ); + if ( chromeos_style_sharpening_strength_env != NULL ) + { + sscanf ( chromeos_style_sharpening_strength_env, "%d", &chromeos_style_sharpening_strength ); + if (chromeos_style_sharpening_strength > 100 ) chromeos_style_sharpening_strength = 100; + else if (chromeos_style_sharpening_strength < 0 ) chromeos_style_sharpening_strength = 0; + } + checked_chromeos_style_sharpening_strength = 1; + } /* check glyph image format */ if ( slot->format != render->glyph_format ) @@ -126,10 +195,33 @@ if ( mode != required_mode ) return Smooth_Err_Cannot_Render_Glyph; - outline = &slot->outline; - + +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){ /*printf ("SCALING ");*/ FT_Outline_Transform( outline, &scaleMat ); } + FT_Outline_Translate( outline, translate_value+8, 0 ); + FT_Outline_Embolden(outline,64.0/scale_value - 64.0 ); + + /*FT_FREE( bitmap->buffer ); + FT_FREE( outline_orig );*/ + } + else + { + outline = &slot->outline; + FT_Outline_Copy(outline, outline_orig); + } + /* translate the outline to the new origin if needed */ - if ( origin ) + if (align_called == 0){ + if ( origin ) FT_Outline_Translate( outline, origin->x, origin->y ); /* compute the control box, and grid fit it */ @@ -143,8 +235,8 @@ if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) { FT_ERROR(( "ft_smooth_render_generic: glyph too large:" - " xMin = %d, xMax = %d\n", - cbox.xMin >> 6, cbox.xMax >> 6 )); + " xMin = %d, xMax = %d\n", + cbox.xMin >> 6, cbox.xMax >> 6 )); return Smooth_Err_Raster_Overflow; } else @@ -213,7 +306,7 @@ } #endif - + } #if FT_UINT_MAX > 0xFFFFU /* Required check is ( pitch * height < FT_ULONG_MAX ), */ @@ -234,7 +327,7 @@ bitmap->pitch = pitch; /* translate outline to render it into the bitmap */ - FT_Outline_Translate( outline, -x_shift, -y_shift ); + if (align_called == 0) FT_Outline_Translate( outline, -x_shift, -y_shift ); if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) goto Exit; @@ -283,9 +376,33 @@ vec->y /= 3; } + if ( slot->library->lcd_stem_align_func && align_called == 0 ) + slot->library->lcd_stem_align_func ( bitmap, mode, slot, &translate_value, &scale_value ); + + if (translate_value != 0 && align_called == 0) + { + /*printf( "%d ", translate_value); */ + + align_called = 1; + goto RERENDER; + } + + /* Chrome OS sharpening */ + /* These should be controllable */ + FT_Byte cutoff = (FT_Byte)(0.5 * 255.0) * (chromeos_style_sharpening_strength / 100.0); + double gamma_value = 1; + /* sharpen the glyphs */ + if (chromeos_style_sharpening_strength > 0) + _ft_subpixel_sharpen( bitmap, mode, cutoff, gamma_value ); + /* END Chrome OS sharpening */ + if ( slot->library->lcd_filter_func ) slot->library->lcd_filter_func( bitmap, mode, slot->library ); + /* put back original outline for artificial embolen or italic */ /*DOESNT SEEM TO WORK*/ + if (align_called == 1) FT_Outline_Copy(outline_orig, outline); + + #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ /* render outline into bitmap */ diff -Nur freetype-subpixel-enabled/src/truetype/ttgload.c freetype-work/src/truetype/ttgload.c --- freetype-subpixel-enabled/src/truetype/ttgload.c 2011-04-29 18:26:58.224161920 -0500 +++ freetype-work/src/truetype/ttgload.c 2011-04-29 19:30:02.089369847 -0500 @@ -1917,6 +1917,11 @@ subpixel_hinting = FALSE; } + if ( FT_IS_TRICKY( glyph->face ) ) + { + subpixel_hinting = grayscale_hinting = FALSE; + } + exec->enhanced = subpixel_hinting || grayscale_hinting; exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; diff -Nur freetype-subpixel-enabled/src/truetype/ttsubpix.c freetype-work/src/truetype/ttsubpix.c --- freetype-subpixel-enabled/src/truetype/ttsubpix.c 2011-04-29 18:26:58.238162722 -0500 +++ freetype-work/src/truetype/ttsubpix.c 2011-04-29 19:30:02.090369904 -0500 @@ -85,6 +85,9 @@ FT_String* style = face->root.style_name; + /* Don't apply rules if style isn't set */ + if ( !face->root.style_name ) return; + /* loader->exec->sph_tweak_flags = 0; */ /* printf( "%s,%d,%s,%c ", family, ppem, style, glyph_index ); */ diff -Nur freetype-subpixel-enabled/src/truetype/ttsubpix.h freetype-work/src/truetype/ttsubpix.h --- freetype-subpixel-enabled/src/truetype/ttsubpix.h 2011-04-29 18:26:58.241162893 -0500 +++ freetype-work/src/truetype/ttsubpix.h 2011-04-29 19:30:02.092370019 -0500 @@ -607,14 +607,14 @@ { "-Verdana", 12, "Regular", 0 }, { "Verdana", 13, "Regular", 0 }, { "-Courier New", 0, "Bold", 0 }, - { "-Times New Roman", 0, "Regular", 0 }, + { "Times New Roman", 0, "Regular", 0 }, { "Arial", 13, "Regular", 0 }, { "Arial", 14, "Regular", 0 }, { "-Arial", 0, "Bold", 0 }, { "-Tahoma", 0, "Regular", 0 }, { "+++Trebuchet MS", 0, "Regular", 0 }, { "-Trebuchet MS", 0, "Bold", 0 }, - { "-Geneva", 0, "", 0 }, + { "-Georgia", 0, "", 0 }, { "-------", 0, "Regular", 0 }, { "-Segoe UI", 0, "Semibold", 0 }, { "+++Segoe UI", 12, "Regular", 'H' }, @@ -664,7 +664,7 @@ { "-", 0, "Regular", 0 }, { "-Verdana", 12, "Regular", 0 }, { "Verdana", 13, "Regular", 0 }, - { "-Times New Roman", 0, "Regular", 0 }, + { "Times New Roman", 0, "Regular", 0 }, { "-Courier New", 0, "Bold", 0 }, { "-Tahoma", 0, "Regular", 0 }, { "-Courier New", 0, "", 0 },