Werner Lemberg | f13516c | 2005-03-03 17:09:08 +0000 | [diff] [blame] | 1 | /***************************************************************************/ |
| 2 | /* */ |
| 3 | /* afloader.c */ |
| 4 | /* */ |
| 5 | /* Auto-fitter glyph loading routines (body). */ |
| 6 | /* */ |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 7 | /* Copyright 2003-2009, 2011 by */ |
Werner Lemberg | f13516c | 2005-03-03 17:09:08 +0000 | [diff] [blame] | 8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
| 9 | /* */ |
| 10 | /* This file is part of the FreeType project, and may only be used, */ |
| 11 | /* modified, and distributed under the terms of the FreeType project */ |
| 12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
| 13 | /* this file you indicate that you have read the license and */ |
| 14 | /* understand and accept it fully. */ |
| 15 | /* */ |
| 16 | /***************************************************************************/ |
| 17 | |
| 18 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 19 | #include "afloader.h" |
| 20 | #include "afhints.h" |
| 21 | #include "afglobal.h" |
Werner Lemberg | a37745b | 2005-03-23 16:45:24 +0000 | [diff] [blame] | 22 | #include "aferrors.h" |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 23 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 24 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 25 | /* Initialize glyph loader. */ |
| 26 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 27 | FT_LOCAL_DEF( FT_Error ) |
| 28 | af_loader_init( AF_Loader loader, |
| 29 | FT_Memory memory ) |
| 30 | { |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 31 | FT_ZERO( loader ); |
| 32 | |
| 33 | af_glyph_hints_init( &loader->hints, memory ); |
Werner Lemberg | d503b1b | 2011-04-18 19:05:28 +0200 | [diff] [blame] | 34 | #ifdef FT_DEBUG_AUTOFIT |
David Turner | 4060474 | 2006-11-02 16:37:35 +0000 | [diff] [blame] | 35 | _af_debug_hints = &loader->hints; |
| 36 | #endif |
David Turner | 65c7c77 | 2006-04-13 07:51:58 +0000 | [diff] [blame] | 37 | return FT_GlyphLoader_New( memory, &loader->gloader ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 38 | } |
| 39 | |
| 40 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 41 | /* Reset glyph loader and compute globals if necessary. */ |
| 42 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 43 | FT_LOCAL_DEF( FT_Error ) |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 44 | af_loader_reset( AF_Loader loader, |
| 45 | FT_Face face ) |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 46 | { |
Werner Lemberg | a37745b | 2005-03-23 16:45:24 +0000 | [diff] [blame] | 47 | FT_Error error = AF_Err_Ok; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 48 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 49 | |
| 50 | loader->face = face; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 51 | loader->globals = (AF_FaceGlobals)face->autohint.data; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 52 | |
| 53 | FT_GlyphLoader_Rewind( loader->gloader ); |
| 54 | |
| 55 | if ( loader->globals == NULL ) |
| 56 | { |
| 57 | error = af_face_globals_new( face, &loader->globals ); |
| 58 | if ( !error ) |
| 59 | { |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 60 | face->autohint.data = |
| 61 | (FT_Pointer)loader->globals; |
| 62 | face->autohint.finalizer = |
| 63 | (FT_Generic_Finalizer)af_face_globals_free; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 64 | } |
| 65 | } |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 66 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 67 | return error; |
| 68 | } |
| 69 | |
| 70 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 71 | /* Finalize glyph loader. */ |
| 72 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 73 | FT_LOCAL_DEF( void ) |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 74 | af_loader_done( AF_Loader loader ) |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 75 | { |
David Turner | 6a487b5 | 2005-02-28 22:09:07 +0000 | [diff] [blame] | 76 | af_glyph_hints_done( &loader->hints ); |
| 77 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 78 | loader->face = NULL; |
| 79 | loader->globals = NULL; |
| 80 | |
Werner Lemberg | d503b1b | 2011-04-18 19:05:28 +0200 | [diff] [blame] | 81 | #ifdef FT_DEBUG_AUTOFIT |
David Turner | 4060474 | 2006-11-02 16:37:35 +0000 | [diff] [blame] | 82 | _af_debug_hints = NULL; |
| 83 | #endif |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 84 | FT_GlyphLoader_Done( loader->gloader ); |
| 85 | loader->gloader = NULL; |
| 86 | } |
| 87 | |
| 88 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 89 | /* Load a single glyph component. This routine calls itself */ |
| 90 | /* recursively, if necessary, and does the main work of */ |
| 91 | /* `af_loader_load_glyph.' */ |
| 92 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 93 | static FT_Error |
| 94 | af_loader_load_g( AF_Loader loader, |
| 95 | AF_Scaler scaler, |
| 96 | FT_UInt glyph_index, |
| 97 | FT_Int32 load_flags, |
| 98 | FT_UInt depth ) |
| 99 | { |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 100 | FT_Error error; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 101 | FT_Face face = loader->face; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 102 | FT_GlyphLoader gloader = loader->gloader; |
| 103 | AF_ScriptMetrics metrics = loader->metrics; |
| 104 | AF_GlyphHints hints = &loader->hints; |
| 105 | FT_GlyphSlot slot = face->glyph; |
| 106 | FT_Slot_Internal internal = slot->internal; |
| 107 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 108 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 109 | error = FT_Load_Glyph( face, glyph_index, load_flags ); |
| 110 | if ( error ) |
| 111 | goto Exit; |
| 112 | |
| 113 | loader->transformed = internal->glyph_transformed; |
| 114 | if ( loader->transformed ) |
| 115 | { |
| 116 | FT_Matrix inverse; |
| 117 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 118 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 119 | loader->trans_matrix = internal->glyph_matrix; |
| 120 | loader->trans_delta = internal->glyph_delta; |
| 121 | |
| 122 | inverse = loader->trans_matrix; |
| 123 | FT_Matrix_Invert( &inverse ); |
| 124 | FT_Vector_Transform( &loader->trans_delta, &inverse ); |
| 125 | } |
| 126 | |
| 127 | /* set linear metrics */ |
| 128 | slot->linearHoriAdvance = slot->metrics.horiAdvance; |
| 129 | slot->linearVertAdvance = slot->metrics.vertAdvance; |
| 130 | |
| 131 | switch ( slot->format ) |
| 132 | { |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 133 | case FT_GLYPH_FORMAT_OUTLINE: |
| 134 | /* translate the loaded glyph when an internal transform is needed */ |
| 135 | if ( loader->transformed ) |
| 136 | FT_Outline_Translate( &slot->outline, |
| 137 | loader->trans_delta.x, |
| 138 | loader->trans_delta.y ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 139 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 140 | /* copy the outline points in the loader's current */ |
| 141 | /* extra points which is used to keep original glyph coordinates */ |
David Turner | 9fbd2ab | 2005-10-28 16:14:14 +0000 | [diff] [blame] | 142 | error = FT_GLYPHLOADER_CHECK_POINTS( gloader, |
| 143 | slot->outline.n_points + 4, |
| 144 | slot->outline.n_contours ); |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 145 | if ( error ) |
| 146 | goto Exit; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 147 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 148 | FT_ARRAY_COPY( gloader->current.outline.points, |
| 149 | slot->outline.points, |
| 150 | slot->outline.n_points ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 151 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 152 | FT_ARRAY_COPY( gloader->current.outline.contours, |
| 153 | slot->outline.contours, |
| 154 | slot->outline.n_contours ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 155 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 156 | FT_ARRAY_COPY( gloader->current.outline.tags, |
| 157 | slot->outline.tags, |
| 158 | slot->outline.n_points ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 159 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 160 | gloader->current.outline.n_points = slot->outline.n_points; |
| 161 | gloader->current.outline.n_contours = slot->outline.n_contours; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 162 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 163 | /* compute original horizontal phantom points (and ignore */ |
| 164 | /* vertical ones) */ |
| 165 | loader->pp1.x = hints->x_delta; |
| 166 | loader->pp1.y = hints->y_delta; |
| 167 | loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, |
| 168 | hints->x_scale ) + hints->x_delta; |
| 169 | loader->pp2.y = hints->y_delta; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 170 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 171 | /* be sure to check for spacing glyphs */ |
| 172 | if ( slot->outline.n_points == 0 ) |
| 173 | goto Hint_Metrics; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 174 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 175 | /* now load the slot image into the auto-outline and run the */ |
| 176 | /* automatic hinting process */ |
Werner Lemberg | 44c655b | 2008-02-17 08:22:08 +0000 | [diff] [blame] | 177 | if ( metrics->clazz->script_hints_apply ) |
| 178 | metrics->clazz->script_hints_apply( hints, |
| 179 | &gloader->current.outline, |
| 180 | metrics ); |
David Turner | e664efa | 2004-06-04 17:41:59 +0000 | [diff] [blame] | 181 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 182 | /* we now need to adjust the metrics according to the change in */ |
| 183 | /* width/positioning that occurred during the hinting process */ |
David Turner | d91eebd | 2007-01-26 15:05:41 +0000 | [diff] [blame] | 184 | if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 185 | { |
Werner Lemberg | 607dec7 | 2007-05-15 06:49:37 +0000 | [diff] [blame] | 186 | FT_Pos old_rsb, old_lsb, new_lsb; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 187 | FT_Pos pp1x_uh, pp2x_uh; |
Werner Lemberg | f13516c | 2005-03-03 17:09:08 +0000 | [diff] [blame] | 188 | AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 189 | AF_Edge edge1 = axis->edges; /* leftmost edge */ |
| 190 | AF_Edge edge2 = edge1 + |
| 191 | axis->num_edges - 1; /* rightmost edge */ |
| 192 | |
Werner Lemberg | b36bf52 | 2006-01-22 07:09:54 +0000 | [diff] [blame] | 193 | |
Wu, Chia-I (吳佳一) | 4cdb45c | 2006-02-09 14:17:04 +0000 | [diff] [blame] | 194 | if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 195 | { |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 196 | old_rsb = loader->pp2.x - edge2->opos; |
| 197 | old_lsb = edge1->opos; |
| 198 | new_lsb = edge1->pos; |
Werner Lemberg | 89d4e4b | 2004-06-05 06:27:08 +0000 | [diff] [blame] | 199 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 200 | /* remember unhinted values to later account */ |
| 201 | /* for rounding errors */ |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 202 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 203 | pp1x_uh = new_lsb - old_lsb; |
| 204 | pp2x_uh = edge2->pos + old_rsb; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 205 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 206 | /* prefer too much space over too little space */ |
| 207 | /* for very small sizes */ |
Werner Lemberg | 89d4e4b | 2004-06-05 06:27:08 +0000 | [diff] [blame] | 208 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 209 | if ( old_lsb < 24 ) |
David Turner | 2ef3e0f | 2007-02-12 21:28:21 +0000 | [diff] [blame] | 210 | pp1x_uh -= 8; |
Werner Lemberg | 89d4e4b | 2004-06-05 06:27:08 +0000 | [diff] [blame] | 211 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 212 | if ( old_rsb < 24 ) |
David Turner | 2ef3e0f | 2007-02-12 21:28:21 +0000 | [diff] [blame] | 213 | pp2x_uh += 8; |
Werner Lemberg | 89d4e4b | 2004-06-05 06:27:08 +0000 | [diff] [blame] | 214 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 215 | loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); |
| 216 | loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); |
Werner Lemberg | 89d4e4b | 2004-06-05 06:27:08 +0000 | [diff] [blame] | 217 | |
David Turner | 2ef3e0f | 2007-02-12 21:28:21 +0000 | [diff] [blame] | 218 | if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) |
David Turner | dbf3b43 | 2006-12-07 21:18:09 +0000 | [diff] [blame] | 219 | loader->pp1.x -= 64; |
| 220 | |
David Turner | 2ef3e0f | 2007-02-12 21:28:21 +0000 | [diff] [blame] | 221 | if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) |
David Turner | dbf3b43 | 2006-12-07 21:18:09 +0000 | [diff] [blame] | 222 | loader->pp2.x += 64; |
| 223 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 224 | slot->lsb_delta = loader->pp1.x - pp1x_uh; |
| 225 | slot->rsb_delta = loader->pp2.x - pp2x_uh; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 226 | } |
| 227 | else |
| 228 | { |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 229 | FT_Pos pp1x = loader->pp1.x; |
| 230 | FT_Pos pp2x = loader->pp2.x; |
| 231 | |
David Turner | 2ce9203 | 2006-03-23 20:58:20 +0000 | [diff] [blame] | 232 | |
David Turner | d91eebd | 2007-01-26 15:05:41 +0000 | [diff] [blame] | 233 | loader->pp1.x = FT_PIX_ROUND( pp1x ); |
| 234 | loader->pp2.x = FT_PIX_ROUND( pp2x ); |
David Turner | 2ce9203 | 2006-03-23 20:58:20 +0000 | [diff] [blame] | 235 | |
| 236 | slot->lsb_delta = loader->pp1.x - pp1x; |
| 237 | slot->rsb_delta = loader->pp2.x - pp2x; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 238 | } |
| 239 | } |
David Turner | d91eebd | 2007-01-26 15:05:41 +0000 | [diff] [blame] | 240 | else |
| 241 | { |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 242 | FT_Pos pp1x = loader->pp1.x; |
| 243 | FT_Pos pp2x = loader->pp2.x; |
| 244 | |
David Turner | d91eebd | 2007-01-26 15:05:41 +0000 | [diff] [blame] | 245 | |
| 246 | loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); |
David Turner | a7ee608 | 2007-01-30 10:33:53 +0000 | [diff] [blame] | 247 | loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); |
David Turner | d91eebd | 2007-01-26 15:05:41 +0000 | [diff] [blame] | 248 | |
| 249 | slot->lsb_delta = loader->pp1.x - pp1x; |
| 250 | slot->rsb_delta = loader->pp2.x - pp2x; |
| 251 | } |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 252 | |
| 253 | /* good, we simply add the glyph to our loader's base */ |
| 254 | FT_GlyphLoader_Add( gloader ); |
| 255 | break; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 256 | |
| 257 | case FT_GLYPH_FORMAT_COMPOSITE: |
| 258 | { |
| 259 | FT_UInt nn, num_subglyphs = slot->num_subglyphs; |
| 260 | FT_UInt num_base_subgs, start_point; |
| 261 | FT_SubGlyph subglyph; |
| 262 | |
| 263 | |
| 264 | start_point = gloader->base.outline.n_points; |
| 265 | |
| 266 | /* first of all, copy the subglyph descriptors in the glyph loader */ |
| 267 | error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); |
| 268 | if ( error ) |
| 269 | goto Exit; |
| 270 | |
| 271 | FT_ARRAY_COPY( gloader->current.subglyphs, |
| 272 | slot->subglyphs, |
| 273 | num_subglyphs ); |
| 274 | |
| 275 | gloader->current.num_subglyphs = num_subglyphs; |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 276 | num_base_subgs = gloader->base.num_subglyphs; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 277 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 278 | /* now read each subglyph independently */ |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 279 | for ( nn = 0; nn < num_subglyphs; nn++ ) |
| 280 | { |
| 281 | FT_Vector pp1, pp2; |
| 282 | FT_Pos x, y; |
| 283 | FT_UInt num_points, num_new_points, num_base_points; |
| 284 | |
| 285 | |
| 286 | /* gloader.current.subglyphs can change during glyph loading due */ |
| 287 | /* to re-allocation -- we must recompute the current subglyph on */ |
| 288 | /* each iteration */ |
| 289 | subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
| 290 | |
| 291 | pp1 = loader->pp1; |
| 292 | pp2 = loader->pp2; |
| 293 | |
| 294 | num_base_points = gloader->base.outline.n_points; |
| 295 | |
| 296 | error = af_loader_load_g( loader, scaler, subglyph->index, |
| 297 | load_flags, depth + 1 ); |
| 298 | if ( error ) |
| 299 | goto Exit; |
| 300 | |
| 301 | /* recompute subglyph pointer */ |
| 302 | subglyph = gloader->base.subglyphs + num_base_subgs + nn; |
| 303 | |
| 304 | if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) |
| 305 | { |
| 306 | pp1 = loader->pp1; |
| 307 | pp2 = loader->pp2; |
| 308 | } |
| 309 | else |
| 310 | { |
| 311 | loader->pp1 = pp1; |
| 312 | loader->pp2 = pp2; |
| 313 | } |
| 314 | |
| 315 | num_points = gloader->base.outline.n_points; |
| 316 | num_new_points = num_points - num_base_points; |
| 317 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 318 | /* now perform the transformation required for this subglyph */ |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 319 | |
| 320 | if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | |
| 321 | FT_SUBGLYPH_FLAG_XY_SCALE | |
| 322 | FT_SUBGLYPH_FLAG_2X2 ) ) |
| 323 | { |
| 324 | FT_Vector* cur = gloader->base.outline.points + |
| 325 | num_base_points; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 326 | FT_Vector* limit = cur + num_new_points; |
| 327 | |
| 328 | |
David Turner | 65c7c77 | 2006-04-13 07:51:58 +0000 | [diff] [blame] | 329 | for ( ; cur < limit; cur++ ) |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 330 | FT_Vector_Transform( cur, &subglyph->transform ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 331 | } |
| 332 | |
| 333 | /* apply offset */ |
| 334 | |
| 335 | if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) |
| 336 | { |
| 337 | FT_Int k = subglyph->arg1; |
| 338 | FT_UInt l = subglyph->arg2; |
| 339 | FT_Vector* p1; |
| 340 | FT_Vector* p2; |
| 341 | |
| 342 | |
| 343 | if ( start_point + k >= num_base_points || |
| 344 | l >= (FT_UInt)num_new_points ) |
| 345 | { |
Werner Lemberg | a37745b | 2005-03-23 16:45:24 +0000 | [diff] [blame] | 346 | error = AF_Err_Invalid_Composite; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 347 | goto Exit; |
| 348 | } |
| 349 | |
| 350 | l += num_base_points; |
| 351 | |
| 352 | /* for now, only use the current point coordinates; */ |
| 353 | /* we may consider another approach in the near future */ |
| 354 | p1 = gloader->base.outline.points + start_point + k; |
| 355 | p2 = gloader->base.outline.points + start_point + l; |
| 356 | |
| 357 | x = p1->x - p2->x; |
| 358 | y = p1->y - p2->y; |
| 359 | } |
| 360 | else |
| 361 | { |
| 362 | x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; |
| 363 | y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; |
| 364 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 365 | x = FT_PIX_ROUND( x ); |
| 366 | y = FT_PIX_ROUND( y ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 367 | } |
| 368 | |
| 369 | { |
| 370 | FT_Outline dummy = gloader->base.outline; |
| 371 | |
| 372 | |
| 373 | dummy.points += num_base_points; |
| 374 | dummy.n_points = (short)num_new_points; |
| 375 | |
| 376 | FT_Outline_Translate( &dummy, x, y ); |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | break; |
| 381 | |
| 382 | default: |
| 383 | /* we don't support other formats (yet?) */ |
Werner Lemberg | a37745b | 2005-03-23 16:45:24 +0000 | [diff] [blame] | 384 | error = AF_Err_Unimplemented_Feature; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 385 | } |
| 386 | |
| 387 | Hint_Metrics: |
| 388 | if ( depth == 0 ) |
| 389 | { |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 390 | FT_BBox bbox; |
| 391 | FT_Vector vvector; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 392 | |
| 393 | |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 394 | vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; |
| 395 | vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; |
| 396 | vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); |
| 397 | vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); |
| 398 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 399 | /* transform the hinted outline if needed */ |
| 400 | if ( loader->transformed ) |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 401 | { |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 402 | FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 403 | FT_Vector_Transform( &vvector, &loader->trans_matrix ); |
| 404 | } |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 405 | #if 1 |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 406 | /* we must translate our final outline by -pp1.x and compute */ |
| 407 | /* the new metrics */ |
| 408 | if ( loader->pp1.x ) |
| 409 | FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 410 | #endif |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 411 | FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); |
| 412 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 413 | bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); |
| 414 | bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); |
| 415 | bbox.xMax = FT_PIX_CEIL( bbox.xMax ); |
| 416 | bbox.yMax = FT_PIX_CEIL( bbox.yMax ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 417 | |
| 418 | slot->metrics.width = bbox.xMax - bbox.xMin; |
| 419 | slot->metrics.height = bbox.yMax - bbox.yMin; |
| 420 | slot->metrics.horiBearingX = bbox.xMin; |
| 421 | slot->metrics.horiBearingY = bbox.yMax; |
| 422 | |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 423 | slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); |
| 424 | slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); |
| 425 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 426 | /* for mono-width fonts (like Andale, Courier, etc.) we need */ |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 427 | /* to keep the original rounded advance width; ditto for */ |
| 428 | /* digits if all have the same advance width */ |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 429 | #if 0 |
| 430 | if ( !FT_IS_FIXED_WIDTH( slot->face ) ) |
| 431 | slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; |
| 432 | else |
| 433 | slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, |
| 434 | x_scale ); |
| 435 | #else |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 436 | if ( FT_IS_FIXED_WIDTH( slot->face ) || |
| 437 | ( af_face_globals_is_digit( loader->globals, glyph_index ) && |
| 438 | metrics->digits_have_same_width ) ) |
David Turner | 23553d6 | 2007-03-26 13:37:17 +0000 | [diff] [blame] | 439 | { |
David Turner | e664efa | 2004-06-04 17:41:59 +0000 | [diff] [blame] | 440 | slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, |
| 441 | metrics->scaler.x_scale ); |
David Turner | 23553d6 | 2007-03-26 13:37:17 +0000 | [diff] [blame] | 442 | |
Werner Lemberg | 644b1ad | 2007-03-28 21:17:11 +0000 | [diff] [blame] | 443 | /* Set delta values to 0. Otherwise code that uses them is */ |
| 444 | /* going to ruin the fixed advance width. */ |
David Turner | 23553d6 | 2007-03-26 13:37:17 +0000 | [diff] [blame] | 445 | slot->lsb_delta = 0; |
| 446 | slot->rsb_delta = 0; |
| 447 | } |
Werner Lemberg | 8b84c9d | 2009-04-27 19:40:35 +0200 | [diff] [blame] | 448 | else |
| 449 | { |
| 450 | /* non-spacing glyphs must stay as-is */ |
| 451 | if ( slot->metrics.horiAdvance ) |
| 452 | slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; |
| 453 | } |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 454 | #endif |
| 455 | |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 456 | slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 457 | metrics->scaler.y_scale ); |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 458 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 459 | slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); |
Wu, Chia-I (吳佳一) | 2e48a1a | 2006-02-27 09:18:07 +0000 | [diff] [blame] | 460 | slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 461 | |
| 462 | /* now copy outline into glyph slot */ |
| 463 | FT_GlyphLoader_Rewind( internal->loader ); |
| 464 | error = FT_GlyphLoader_CopyPoints( internal->loader, gloader ); |
| 465 | if ( error ) |
| 466 | goto Exit; |
| 467 | |
| 468 | slot->outline = internal->loader->base.outline; |
| 469 | slot->format = FT_GLYPH_FORMAT_OUTLINE; |
| 470 | } |
| 471 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 472 | Exit: |
| 473 | return error; |
| 474 | } |
| 475 | |
| 476 | |
Werner Lemberg | 6cfbb23 | 2011-02-26 17:32:38 +0100 | [diff] [blame] | 477 | /* Load a glyph. */ |
| 478 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 479 | FT_LOCAL_DEF( FT_Error ) |
| 480 | af_loader_load_glyph( AF_Loader loader, |
| 481 | FT_Face face, |
| 482 | FT_UInt gindex, |
| 483 | FT_UInt32 load_flags ) |
| 484 | { |
| 485 | FT_Error error; |
| 486 | FT_Size size = face->size; |
| 487 | AF_ScalerRec scaler; |
| 488 | |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 489 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 490 | if ( !size ) |
Werner Lemberg | a37745b | 2005-03-23 16:45:24 +0000 | [diff] [blame] | 491 | return AF_Err_Invalid_Argument; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 492 | |
| 493 | FT_ZERO( &scaler ); |
| 494 | |
| 495 | scaler.face = face; |
| 496 | scaler.x_scale = size->metrics.x_scale; |
| 497 | scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ |
| 498 | scaler.y_scale = size->metrics.y_scale; |
| 499 | scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ |
| 500 | |
| 501 | scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); |
| 502 | scaler.flags = 0; /* XXX: fix this */ |
| 503 | |
| 504 | error = af_loader_reset( loader, face ); |
| 505 | if ( !error ) |
| 506 | { |
| 507 | AF_ScriptMetrics metrics; |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 508 | FT_UInt options = 0; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 509 | |
Werner Lemberg | 49e18b8 | 2007-06-11 21:15:09 +0000 | [diff] [blame] | 510 | |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 511 | #ifdef FT_OPTION_AUTOFIT2 |
| 512 | /* XXX: undocumented hook to activate the latin2 hinter */ |
Werner Lemberg | 49e18b8 | 2007-06-11 21:15:09 +0000 | [diff] [blame] | 513 | if ( load_flags & ( 1UL << 20 ) ) |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 514 | options = 2; |
| 515 | #endif |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 516 | |
| 517 | error = af_face_globals_get_metrics( loader->globals, gindex, |
David Turner | b792017 | 2007-06-11 05:37:35 +0000 | [diff] [blame] | 518 | options, &metrics ); |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 519 | if ( !error ) |
| 520 | { |
| 521 | loader->metrics = metrics; |
| 522 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 523 | if ( metrics->clazz->script_metrics_scale ) |
| 524 | metrics->clazz->script_metrics_scale( metrics, &scaler ); |
David Turner | b9c22af | 2005-03-01 15:48:29 +0000 | [diff] [blame] | 525 | else |
| 526 | metrics->scaler = scaler; |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 527 | |
| 528 | load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; |
| 529 | load_flags &= ~FT_LOAD_RENDER; |
| 530 | |
Werner Lemberg | 44c655b | 2008-02-17 08:22:08 +0000 | [diff] [blame] | 531 | if ( metrics->clazz->script_hints_init ) |
| 532 | { |
| 533 | error = metrics->clazz->script_hints_init( &loader->hints, |
| 534 | metrics ); |
| 535 | if ( error ) |
| 536 | goto Exit; |
| 537 | } |
David Turner | e664efa | 2004-06-04 17:41:59 +0000 | [diff] [blame] | 538 | |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 539 | error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); |
| 540 | } |
| 541 | } |
David Turner | e664efa | 2004-06-04 17:41:59 +0000 | [diff] [blame] | 542 | Exit: |
Werner Lemberg | 8bb07e6 | 2004-03-27 08:43:17 +0000 | [diff] [blame] | 543 | return error; |
| 544 | } |
Werner Lemberg | b19b081 | 2005-03-02 11:24:23 +0000 | [diff] [blame] | 545 | |
| 546 | |
| 547 | /* END */ |