source: trunk/poppler/freetype-2.1.10/src/autofit/afloader.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 15.5 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  afloader.c                                                             */
4/*                                                                         */
5/*    Auto-fitter glyph loading routines (body).                           */
6/*                                                                         */
7/*  Copyright 2003, 2004, 2005 by                                          */
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
19#include "afloader.h"
20#include "afhints.h"
21#include "afglobal.h"
22#include "aflatin.h"
23#include "aferrors.h"
24
25
26  FT_LOCAL_DEF( FT_Error )
27  af_loader_init( AF_Loader  loader,
28                  FT_Memory  memory )
29  {
30    FT_Error  error;
31
32
33    FT_ZERO( loader );
34
35    af_glyph_hints_init( &loader->hints, memory );
36
37    error = FT_GlyphLoader_New( memory, &loader->gloader );
38    if ( !error )
39    {
40      error = FT_GlyphLoader_CreateExtra( loader->gloader );
41      if ( error )
42      {
43        FT_GlyphLoader_Done( loader->gloader );
44        loader->gloader = NULL;
45      }
46    }
47    return error;
48  }
49
50
51  FT_LOCAL_DEF( FT_Error )
52  af_loader_reset( AF_Loader  loader,
53                   FT_Face    face )
54  {
55    FT_Error  error = AF_Err_Ok;
56
57
58    loader->face    = face;
59    loader->globals = (AF_FaceGlobals)face->autohint.data;
60
61    FT_GlyphLoader_Rewind( loader->gloader );
62
63    if ( loader->globals == NULL )
64    {
65      error = af_face_globals_new( face, &loader->globals );
66      if ( !error )
67      {
68        face->autohint.data =
69          (FT_Pointer)loader->globals;
70        face->autohint.finalizer =
71          (FT_Generic_Finalizer)af_face_globals_free;
72      }
73    }
74
75    return error;
76  }
77
78
79  FT_LOCAL_DEF( void )
80  af_loader_done( AF_Loader  loader )
81  {
82    af_glyph_hints_done( &loader->hints );
83
84    loader->face    = NULL;
85    loader->globals = NULL;
86
87    FT_GlyphLoader_Done( loader->gloader );
88    loader->gloader = NULL;
89  }
90
91
92  static FT_Error
93  af_loader_load_g( AF_Loader  loader,
94                    AF_Scaler  scaler,
95                    FT_UInt    glyph_index,
96                    FT_Int32   load_flags,
97                    FT_UInt    depth )
98  {
99    FT_Error          error;
100    FT_Face           face     = loader->face;
101    FT_GlyphLoader    gloader  = loader->gloader;
102    AF_ScriptMetrics  metrics  = loader->metrics;
103    AF_GlyphHints     hints    = &loader->hints;
104    FT_GlyphSlot      slot     = face->glyph;
105    FT_Slot_Internal  internal = slot->internal;
106
107
108    error = FT_Load_Glyph( face, glyph_index, load_flags );
109    if ( error )
110      goto Exit;
111
112    loader->transformed = internal->glyph_transformed;
113    if ( loader->transformed )
114    {
115      FT_Matrix  inverse;
116
117
118      loader->trans_matrix = internal->glyph_matrix;
119      loader->trans_delta  = internal->glyph_delta;
120
121      inverse = loader->trans_matrix;
122      FT_Matrix_Invert( &inverse );
123      FT_Vector_Transform( &loader->trans_delta, &inverse );
124    }
125
126    /* set linear metrics */
127    slot->linearHoriAdvance = slot->metrics.horiAdvance;
128    slot->linearVertAdvance = slot->metrics.vertAdvance;
129
130    switch ( slot->format )
131    {
132    case FT_GLYPH_FORMAT_OUTLINE:
133      /* translate the loaded glyph when an internal transform is needed */
134      if ( loader->transformed )
135        FT_Outline_Translate( &slot->outline,
136                              loader->trans_delta.x,
137                              loader->trans_delta.y );
138
139      /* copy the outline points in the loader's current               */
140      /* extra points which is used to keep original glyph coordinates */
141      error = FT_GlyphLoader_CheckPoints( gloader,
142                                          slot->outline.n_points + 4,
143                                          slot->outline.n_contours );
144      if ( error )
145        goto Exit;
146
147      FT_ARRAY_COPY( gloader->current.outline.points,
148                     slot->outline.points,
149                     slot->outline.n_points );
150
151      FT_ARRAY_COPY( gloader->current.extra_points,
152                     slot->outline.points,
153                     slot->outline.n_points );
154
155      FT_ARRAY_COPY( gloader->current.outline.contours,
156                     slot->outline.contours,
157                     slot->outline.n_contours );
158
159      FT_ARRAY_COPY( gloader->current.outline.tags,
160                     slot->outline.tags,
161                     slot->outline.n_points );
162
163      gloader->current.outline.n_points   = slot->outline.n_points;
164      gloader->current.outline.n_contours = slot->outline.n_contours;
165
166      /* compute original horizontal phantom points (and ignore */
167      /* vertical ones)                                         */
168      loader->pp1.x = hints->x_delta;
169      loader->pp1.y = hints->y_delta;
170      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
171                                 hints->x_scale ) + hints->x_delta;
172      loader->pp2.y = hints->y_delta;
173
174      /* be sure to check for spacing glyphs */
175      if ( slot->outline.n_points == 0 )
176        goto Hint_Metrics;
177
178      /* now load the slot image into the auto-outline and run the */
179      /* automatic hinting process                                 */
180      metrics->clazz->script_hints_apply( hints,
181                                          &gloader->current.outline,
182                                          metrics );
183
184      /* we now need to hint the metrics according to the change in */
185      /* width/positioning that occured during the hinting process  */
186      {
187        FT_Pos        old_advance, old_rsb, old_lsb, new_lsb;
188        FT_Pos        pp1x_uh, pp2x_uh;
189        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
190        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
191        AF_Edge       edge2 = edge1 +
192                              axis->num_edges - 1; /* rightmost edge */
193
194
195        if ( axis->num_edges > 1 )
196        {
197          old_advance = loader->pp2.x;
198          old_rsb     = old_advance - edge2->opos;
199          old_lsb     = edge1->opos;
200          new_lsb     = edge1->pos;
201
202          /* remember unhinted values to later account */
203          /* for rounding errors                       */
204
205          pp1x_uh = new_lsb    - old_lsb;
206          pp2x_uh = edge2->pos + old_rsb;
207
208          /* prefer too much space over too little space */
209          /* for very small sizes                        */
210
211          if ( old_lsb < 24 )
212            pp1x_uh -= 5;
213
214          if ( old_rsb < 24 )
215            pp2x_uh += 5;
216
217          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
218          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
219
220          slot->lsb_delta = loader->pp1.x - pp1x_uh;
221          slot->rsb_delta = loader->pp2.x - pp2x_uh;
222
223#if 0
224          /* try to fix certain bad advance computations */
225          if ( loader->pp2.x + loader->pp1.x == edge2->pos && old_rsb > 4 )
226            loader->pp2.x += 64;
227#endif
228
229        }
230        else
231        {
232          loader->pp1.x = FT_PIX_ROUND( loader->pp1.x );
233          loader->pp2.x = FT_PIX_ROUND( loader->pp2.x );
234        }
235      }
236
237      /* good, we simply add the glyph to our loader's base */
238      FT_GlyphLoader_Add( gloader );
239      break;
240
241    case FT_GLYPH_FORMAT_COMPOSITE:
242      {
243        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
244        FT_UInt      num_base_subgs, start_point;
245        FT_SubGlyph  subglyph;
246
247
248        start_point = gloader->base.outline.n_points;
249
250        /* first of all, copy the subglyph descriptors in the glyph loader */
251        error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
252        if ( error )
253          goto Exit;
254
255        FT_ARRAY_COPY( gloader->current.subglyphs,
256                       slot->subglyphs,
257                       num_subglyphs );
258
259        gloader->current.num_subglyphs = num_subglyphs;
260        num_base_subgs                 = gloader->base.num_subglyphs;
261
262        /* now, read each subglyph independently */
263        for ( nn = 0; nn < num_subglyphs; nn++ )
264        {
265          FT_Vector  pp1, pp2;
266          FT_Pos     x, y;
267          FT_UInt    num_points, num_new_points, num_base_points;
268
269
270          /* gloader.current.subglyphs can change during glyph loading due */
271          /* to re-allocation -- we must recompute the current subglyph on */
272          /* each iteration                                                */
273          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
274
275          pp1 = loader->pp1;
276          pp2 = loader->pp2;
277
278          num_base_points = gloader->base.outline.n_points;
279
280          error = af_loader_load_g( loader, scaler, subglyph->index,
281                                    load_flags, depth + 1 );
282          if ( error )
283            goto Exit;
284
285          /* recompute subglyph pointer */
286          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
287
288          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
289          {
290            pp1 = loader->pp1;
291            pp2 = loader->pp2;
292          }
293          else
294          {
295            loader->pp1 = pp1;
296            loader->pp2 = pp2;
297          }
298
299          num_points     = gloader->base.outline.n_points;
300          num_new_points = num_points - num_base_points;
301
302          /* now perform the transform required for this subglyph */
303
304          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
305                                   FT_SUBGLYPH_FLAG_XY_SCALE |
306                                   FT_SUBGLYPH_FLAG_2X2      ) )
307          {
308            FT_Vector*  cur   = gloader->base.outline.points +
309                                num_base_points;
310            FT_Vector*  org   = gloader->base.extra_points +
311                                num_base_points;
312            FT_Vector*  limit = cur + num_new_points;
313
314
315            for ( ; cur < limit; cur++, org++ )
316            {
317              FT_Vector_Transform( cur, &subglyph->transform );
318              FT_Vector_Transform( org, &subglyph->transform );
319            }
320          }
321
322          /* apply offset */
323
324          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
325          {
326            FT_Int      k = subglyph->arg1;
327            FT_UInt     l = subglyph->arg2;
328            FT_Vector*  p1;
329            FT_Vector*  p2;
330
331
332            if ( start_point + k >= num_base_points         ||
333                               l >= (FT_UInt)num_new_points )
334            {
335              error = AF_Err_Invalid_Composite;
336              goto Exit;
337            }
338
339            l += num_base_points;
340
341            /* for now, only use the current point coordinates;    */
342            /* we may consider another approach in the near future */
343            p1 = gloader->base.outline.points + start_point + k;
344            p2 = gloader->base.outline.points + start_point + l;
345
346            x = p1->x - p2->x;
347            y = p1->y - p2->y;
348          }
349          else
350          {
351            x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
352            y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
353
354            x = FT_PIX_ROUND( x );
355            y = FT_PIX_ROUND( y );
356          }
357
358          {
359            FT_Outline  dummy = gloader->base.outline;
360
361
362            dummy.points  += num_base_points;
363            dummy.n_points = (short)num_new_points;
364
365            FT_Outline_Translate( &dummy, x, y );
366          }
367        }
368      }
369      break;
370
371    default:
372      /* we don't support other formats (yet?) */
373      error = AF_Err_Unimplemented_Feature;
374    }
375
376  Hint_Metrics:
377    if ( depth == 0 )
378    {
379      FT_BBox  bbox;
380
381
382      /* transform the hinted outline if needed */
383      if ( loader->transformed )
384        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
385
386      /* we must translate our final outline by -pp1.x and compute */
387      /* the new metrics                                           */
388      if ( loader->pp1.x )
389        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
390
391      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
392
393      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
394      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
395      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
396      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );
397
398      slot->metrics.width        = bbox.xMax - bbox.xMin;
399      slot->metrics.height       = bbox.yMax - bbox.yMin;
400      slot->metrics.horiBearingX = bbox.xMin;
401      slot->metrics.horiBearingY = bbox.yMax;
402
403      /* for mono-width fonts (like Andale, Courier, etc.) we need */
404      /* to keep the original rounded advance width                */
405#if 0
406      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
407        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
408      else
409        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
410                                               x_scale );
411#else
412      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
413        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
414      else
415        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
416                                               metrics->scaler.x_scale );
417#endif
418
419      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
420
421      /* now copy outline into glyph slot */
422      FT_GlyphLoader_Rewind( internal->loader );
423      error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
424      if ( error )
425        goto Exit;
426
427      slot->outline = internal->loader->base.outline;
428      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
429    }
430
431#ifdef DEBUG_HINTER
432    af_debug_hinter = hinter;
433#endif
434
435  Exit:
436    return error;
437  }
438
439
440  FT_LOCAL_DEF( FT_Error )
441  af_loader_load_glyph( AF_Loader  loader,
442                        FT_Face    face,
443                        FT_UInt    gindex,
444                        FT_UInt32  load_flags )
445  {
446    FT_Error      error;
447    FT_Size       size = face->size;
448    AF_ScalerRec  scaler;
449
450
451    if ( !size )
452      return AF_Err_Invalid_Argument;
453
454    FT_ZERO( &scaler );
455
456    scaler.face    = face;
457    scaler.x_scale = size->metrics.x_scale;
458    scaler.x_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
459    scaler.y_scale = size->metrics.y_scale;
460    scaler.y_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
461
462    scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
463    scaler.flags       = 0;  /* XXX: fix this */
464
465    error = af_loader_reset( loader, face );
466    if ( !error )
467    {
468      AF_ScriptMetrics  metrics;
469
470
471      error = af_face_globals_get_metrics( loader->globals, gindex,
472                                           &metrics );
473      if ( !error )
474      {
475        loader->metrics = metrics;
476
477        if ( metrics->clazz->script_metrics_scale )
478          metrics->clazz->script_metrics_scale( metrics, &scaler );
479        else
480          metrics->scaler = scaler;
481
482        load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
483        load_flags &= ~FT_LOAD_RENDER;
484
485        error = metrics->clazz->script_hints_init( &loader->hints, metrics );
486        if ( error )
487          goto Exit;
488
489        error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 );
490      }
491    }
492  Exit:
493    return error;
494  }
495
496
497/* END */
Note: See TracBrowser for help on using the repository browser.