ref: 032e23aab9cee8329554d30c0747549a4ca1e4ae
parent: 9acb09e060259fc3fa6bd4313d4d06f488f940f8
author: David Turner <[email protected]>
date: Thu Jan 30 09:57:38 EST 2003
improvements to the Postscript hinter
--- a/src/pshinter/pshalgo3.c
+++ b/src/pshinter/pshalgo3.c
@@ -456,7 +456,9 @@
return;
}
- /* perform stem snapping when requested */
+ /* perform stem snapping when requested - this is necessary
+ * for monochrome and LCD hinting modes only
+ */
do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
( dimension == 1 && glyph->do_vert_snapping );
@@ -516,14 +518,24 @@
hint->cur_pos = pos;
hint->cur_len = fit_len;
+#if 0
+ /* stem adjustment tries to snap stem widths to standard
+ * ones. this is important to prevent unpleasant rounding
+ * artefacts...
+ */
if ( glyph->do_stem_adjust )
{
if ( len <= 64 )
{
- /* the stem is less than one pixel, we will center it */
- /* around the nearest pixel center */
- /* */
+ /* the stem is less than one pixel, we will center it
+ * around the nearest pixel center
+ */
+#if 1
+ pos = ( pos + (len >> 1) ) & -64;
+#else
+ /* this seems to be a bug !! */
pos = ( pos + ( (len >> 1) & -64 ) );
+#endif
len = 64;
}
else
@@ -531,6 +543,7 @@
len = psh3_dimension_quantize_len( dim, len, 0 );
}
}
+#endif /* 0 */
/* now that we have a good hinted stem width, try to position */
/* the stem along a pixel grid integer coordinate */
@@ -541,7 +554,7 @@
if ( do_snapping )
{
- pos = hint->cur_pos;
+ pos = hint->cur_pos;
len = hint->cur_len;
if ( len < 64 )
@@ -576,6 +589,186 @@
hint->cur_len = len;
}
}
+
+ psh3_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+ if ( ps3_debug_hint_func )
+ ps3_debug_hint_func( hint, dimension );
+#endif
+ }
+ }
+
+
+ /*
+ * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
+ * of stems
+ */
+ static void
+ psh3_hint_align_light( PSH3_Hint hint,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH3_Glyph glyph )
+ {
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( !psh3_hint_is_fitted(hint) )
+ {
+ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ FT_Pos len = FT_MulFix( hint->org_len, scale );
+
+ FT_Pos fit_center;
+ FT_Pos fit_len;
+
+ PSH_AlignmentRec align;
+
+ /* ignore stem alignments when requested through the hint flags */
+ if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+ ( dimension == 1 && !glyph->do_vert_hints ) )
+ {
+ hint->cur_pos = pos;
+ hint->cur_len = len;
+
+ psh3_hint_set_fitted( hint );
+ return;
+ }
+
+ fit_len = len;
+
+ hint->cur_len = fit_len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+
+ if ( dimension == 1 )
+ psh_blues_snap_stem( &globals->blues,
+ hint->org_pos + hint->org_len,
+ hint->org_pos,
+ &align );
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ /* the top of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_top - fit_len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ /* the bottom of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_bot;
+ break;
+
+ case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+ /* both edges of the stem are aligned against blue zones */
+ hint->cur_pos = align.align_bot;
+ hint->cur_len = align.align_top - align.align_bot;
+ break;
+
+ default:
+ {
+ PSH3_Hint parent = hint->parent;
+
+
+ if ( parent )
+ {
+ FT_Pos par_org_center, par_cur_center;
+ FT_Pos cur_org_center, cur_delta;
+
+
+ /* ensure that parent is already fitted */
+ if ( !psh3_hint_is_fitted( parent ) )
+ psh3_hint_align_light( parent, globals, dimension, glyph );
+
+ par_org_center = parent->org_pos + ( parent->org_len / 2);
+ par_cur_center = parent->cur_pos + ( parent->cur_len / 2);
+ cur_org_center = hint->org_pos + ( hint->org_len / 2);
+
+ cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+ pos = par_cur_center + cur_delta - ( len >> 1 );
+ }
+
+ /* Stems less than one pixel wide are easy - we want to
+ * make them as dark as possible, so they must fall within
+ * one pixel. If the stem is split between two pixels
+ * then snap the edge that is nearer to the pixel boundary
+ * to the pixel boundary
+ */
+ if (len <= 64)
+ {
+ if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
+ pos += psh3_hint_snap_stem_side_delta ( pos, len );
+ }
+ /* Position stems other to minimize the amount of mid-grays.
+ * There are, in general, two positions that do this,
+ * illustrated as A) and B) below.
+ *
+ * + + + +
+ *
+ * A) |--------------------------------|
+ * B) |--------------------------------|
+ * C) |--------------------------------|
+ *
+ * Position A) (split the excess stem equally) should be better
+ * for stems of width N + f where f < 0.5
+ *
+ * Position B) (split the deficiency equally) should be better
+ * for stems of width N + f where f > 0.5
+ *
+ * It turns out though that minimizing the total number of lit
+ * pixels is also important, so position C), with one edge
+ * aligned with a pixel boundary is actually preferable
+ * to A). There are also more possibile positions for C) than
+ * for A) or B), so it involves less distortion of the overall
+ * character shape.
+ */
+ else /* len > 64 */
+ {
+ FT_Fixed frac_len = len & 63;
+ FT_Fixed center = pos + ( len >> 1 );
+ FT_Fixed delta_a, delta_b;
+
+ if ( ( len / 64 ) & 1 )
+ {
+ delta_a = ( center & -64 ) + 32 - center;
+ delta_b = ( ( center + 32 ) & - 64 ) - center;
+ }
+ else
+ {
+ delta_a = ( ( center + 32 ) & - 64 ) - center;
+ delta_b = ( center & -64 ) + 32 - center;
+ }
+
+ /* We choose between B) and C) above based on the amount
+ * of fractinal stem width; for small amounts, choose
+ * C) always, for large amounts, B) always, and inbetween,
+ * pick whichever one involves less stem movement.
+ */
+ if (frac_len < 32)
+ {
+ pos += psh3_hint_snap_stem_side_delta ( pos, len );
+ }
+ else if (frac_len < 48)
+ {
+ FT_Fixed side_delta = psh3_hint_snap_stem_side_delta ( pos, len );
+
+ if ( ABS( side_delta ) < ABS( delta_b ) )
+ pos += side_delta;
+ else
+ pos += delta_b;
+ }
+ else
+ {
+ pos += delta_b;
+ }
+ }
+
+ hint->cur_pos = pos;
+ }
+ } /* switch */
psh3_hint_set_fitted( hint );