Fix Type 1 hinting. Type 1 hinting breaks sometimes when mid-charstring hints should have been in the initial hintmap. This fix adds a preprocessing pass that reads all hints and builds the correct initial hintmap first, before proceeding to build the glyph outline. * src/psaux/psintrp.c (cf2_interpT2CharString): New `initial_map_ready' boolean flag. Ignore outline commands and hint changes on first pass. <cf2_cmdENDCHAR>: Add section to build hintmap and rewind.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
diff --git a/ChangeLog b/ChangeLog
index 3ab15c5..7961ebe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2017-09-25 Ewald Hew <ewaldhew@gmail.com>
+ [psaux] Fix Type 1 hinting.
+
+ Type 1 hinting breaks sometimes when mid-charstring hints should
+ have been in the initial hintmap. This fix adds a preprocessing
+ pass that reads all hints and builds the correct initial hintmap
+ first, before proceeding to build the glyph outline.
+
+ * src/psaux/psintrp.c (cf2_interpT2CharString): New
+ `initial_map_ready' boolean flag.
+ Ignore outline commands and hint changes on first pass.
+ <cf2_cmdENDCHAR>: Add section to build hintmap and rewind.
+
+2017-09-25 Ewald Hew <ewaldhew@gmail.com>
+
[psaux] Add tracing for hints.
* src/psaux/pshints.c (cf2_hintmap_dump): New function.
diff --git a/src/psaux/psintrp.c b/src/psaux/psintrp.c
index 77f2632..3e0590f 100644
--- a/src/psaux/psintrp.c
+++ b/src/psaux/psintrp.c
@@ -492,6 +492,7 @@
/* Stuff for Type 1 */
FT_Int known_othersubr_result_cnt = 0;
FT_Bool large_int = FALSE;
+ FT_Bool initial_map_ready = FALSE;
#define PS_STORAGE_SIZE 3
CF2_F16Dot16 results[PS_STORAGE_SIZE]; /* for othersubr results */
FT_Int result_cnt = 0;
@@ -650,6 +651,20 @@
if ( font->isT1 )
{
+ if ( !initial_map_ready &&
+ !( op1 == cf2_cmdHSTEM ||
+ op1 == cf2_cmdVSTEM ||
+ op1 == cf2_cmdHSBW ||
+ op1 == cf2_cmdCALLSUBR ||
+ op1 == cf2_cmdRETURN ||
+ op1 == cf2_cmdESC ||
+ op1 == cf2_cmdENDCHAR ||
+ op1 >= 32 /* Numbers */ ) )
+ {
+ cf2_stack_clear( opStack );
+ continue;
+ }
+
if ( result_cnt > 0 &&
!( op1 == cf2_cmdCALLSUBR ||
op1 == cf2_cmdRETURN ||
@@ -1478,8 +1493,11 @@
if ( builder->metrics_only )
goto exit;
- curX = ADD_INT32( curX, lsb_x );
- curY = ADD_INT32( curY, lsb_y );
+ if ( initial_map_ready )
+ {
+ curX = ADD_INT32( curX, lsb_x );
+ curY = ADD_INT32( curY, lsb_y );
+ }
}
}
break;
@@ -1647,8 +1665,9 @@
if ( arg_cnt != 3 )
goto Unexpected_OtherSubr;
- if ( !decoder->flex_state ||
- decoder->num_flex_vectors != 7 )
+ if ( initial_map_ready &&
+ ( !decoder->flex_state ||
+ decoder->num_flex_vectors != 7 ) )
{
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
" unexpected flex end\n" ));
@@ -1666,6 +1685,9 @@
if ( arg_cnt != 0 )
goto Unexpected_OtherSubr;
+ if ( !initial_map_ready )
+ break;
+
if ( ps_builder_check_points( &decoder->builder, 6 ) )
goto exit;
@@ -1682,6 +1704,9 @@
if ( arg_cnt != 0 )
goto Unexpected_OtherSubr;
+ if ( !initial_map_ready )
+ break;
+
if ( !decoder->flex_state )
{
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
@@ -1728,12 +1753,15 @@
if ( arg_cnt != 1 )
goto Unexpected_OtherSubr;
- cf2_arrstack_clear( &vStemHintArray );
- cf2_arrstack_clear( &hStemHintArray );
+ if ( initial_map_ready )
+ {
+ cf2_arrstack_clear( &vStemHintArray );
+ cf2_arrstack_clear( &hStemHintArray );
- cf2_hintmask_init( &hintMask, error );
- hintMask.isValid = FALSE;
- hintMask.isNew = TRUE;
+ cf2_hintmask_init( &hintMask, error );
+ hintMask.isValid = FALSE;
+ hintMask.isNew = TRUE;
+ }
known_othersubr_result_cnt = 1;
break;
@@ -2281,6 +2309,9 @@
{
FT_TRACE4(( " setcurrentpoint" ));
+ if ( !initial_map_ready )
+ break;
+
/* From the T1 specification, section 6.4: */
/* */
/* The setcurrentpoint command is used only in */
@@ -2351,13 +2382,38 @@
if ( builder->metrics_only )
goto exit;
- curX = ADD_INT32( curX, lsb_x );
+ if ( initial_map_ready )
+ curX = ADD_INT32( curX, lsb_x );
}
break;
case cf2_cmdENDCHAR:
FT_TRACE4(( " endchar\n" ));
+ if ( font->isT1 && !initial_map_ready )
+ {
+ FT_TRACE5(( "cf2_interpT2CharString (Type 1 mode): "
+ "Build initial hintmap, rewinding...\n" ));
+
+ /* Trigger initial hintmap build */
+ cf2_glyphpath_moveTo( &glyphPath, curX, curY );
+
+ initial_map_ready = TRUE;
+
+ /* Change hints routine - clear for rewind */
+ cf2_arrstack_clear( &vStemHintArray );
+ cf2_arrstack_clear( &hStemHintArray );
+
+ cf2_hintmask_init( &hintMask, error );
+ hintMask.isValid = FALSE;
+ hintMask.isNew = TRUE;
+
+ /* Rewind charstring */
+ charstring->ptr = charstring->start;
+
+ break;
+ }
+
if ( cf2_stack_count( opStack ) == 1 ||
cf2_stack_count( opStack ) == 5 )
{