1 /****************************************************************************
2  *
3  * ftadvanc.c
4  *
5  *   Quick computation of advance widths (body).
6  *
7  * Copyright (C) 2008-2021 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 <freetype/internal/ftdebug.h>
20 
21 #include <freetype/ftadvanc.h>
22 #include <freetype/internal/ftobjs.h>
23 
24 
25   static FT_Error
_ft_face_scale_advances(FT_Face face,FT_Fixed * advances,FT_UInt count,FT_Int32 flags)26   _ft_face_scale_advances( FT_Face    face,
27                            FT_Fixed*  advances,
28                            FT_UInt    count,
29                            FT_Int32   flags )
30   {
31     FT_Fixed  scale;
32     FT_UInt   nn;
33 
34 
35     if ( flags & FT_LOAD_NO_SCALE )
36       return FT_Err_Ok;
37 
38     if ( !face->size )
39       return FT_THROW( Invalid_Size_Handle );
40 
41     if ( flags & FT_LOAD_VERTICAL_LAYOUT )
42       scale = face->size->metrics.y_scale;
43     else
44       scale = face->size->metrics.x_scale;
45 
46     /* this must be the same scaling as to get linear{Hori,Vert}Advance */
47     /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c)        */
48 
49     for ( nn = 0; nn < count; nn++ )
50       advances[nn] = FT_MulDiv( advances[nn], scale, 64 );
51 
52     return FT_Err_Ok;
53   }
54 
55 
56    /* at the moment, we can perform fast advance retrieval only in */
57    /* the following cases:                                         */
58    /*                                                              */
59    /*  - unscaled load                                             */
60    /*  - unhinted load                                             */
61    /*  - light-hinted load                                         */
62    /*  - if a variations font, it must have an `HVAR' or `VVAR'    */
63    /*    table (thus the old MM or GX fonts don't qualify; this    */
64    /*    gets checked by the driver-specific functions)            */
65 
66 #define LOAD_ADVANCE_FAST_CHECK( face, flags )                      \
67           ( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING )    || \
68             FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT )
69 
70 
71   /* documentation is in ftadvanc.h */
72 
73   FT_EXPORT_DEF( FT_Error )
FT_Get_Advance(FT_Face face,FT_UInt gindex,FT_Int32 flags,FT_Fixed * padvance)74   FT_Get_Advance( FT_Face    face,
75                   FT_UInt    gindex,
76                   FT_Int32   flags,
77                   FT_Fixed  *padvance )
78   {
79     FT_Face_GetAdvancesFunc  func;
80 
81 
82     if ( !face )
83       return FT_THROW( Invalid_Face_Handle );
84 
85     if ( !padvance )
86       return FT_THROW( Invalid_Argument );
87 
88     if ( gindex >= (FT_UInt)face->num_glyphs )
89       return FT_THROW( Invalid_Glyph_Index );
90 
91     func = face->driver->clazz->get_advances;
92     if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
93     {
94       FT_Error  error;
95 
96 
97       error = func( face, gindex, 1, flags, padvance );
98       if ( !error )
99         return _ft_face_scale_advances( face, padvance, 1, flags );
100 
101       if ( FT_ERR_NEQ( error, Unimplemented_Feature ) )
102         return error;
103     }
104 
105     return FT_Get_Advances( face, gindex, 1, flags, padvance );
106   }
107 
108 
109   /* documentation is in ftadvanc.h */
110 
111   FT_EXPORT_DEF( FT_Error )
FT_Get_Advances(FT_Face face,FT_UInt start,FT_UInt count,FT_Int32 flags,FT_Fixed * padvances)112   FT_Get_Advances( FT_Face    face,
113                    FT_UInt    start,
114                    FT_UInt    count,
115                    FT_Int32   flags,
116                    FT_Fixed  *padvances )
117   {
118     FT_Error  error = FT_Err_Ok;
119 
120     FT_Face_GetAdvancesFunc  func;
121 
122     FT_UInt  num, end, nn;
123     FT_Int   factor;
124 
125 
126     if ( !face )
127       return FT_THROW( Invalid_Face_Handle );
128 
129     if ( !padvances )
130       return FT_THROW( Invalid_Argument );
131 
132     num = (FT_UInt)face->num_glyphs;
133     end = start + count;
134     if ( start >= num || end < start || end > num )
135       return FT_THROW( Invalid_Glyph_Index );
136 
137     if ( count == 0 )
138       return FT_Err_Ok;
139 
140     func = face->driver->clazz->get_advances;
141     if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
142     {
143       error = func( face, start, count, flags, padvances );
144       if ( !error )
145         return _ft_face_scale_advances( face, padvances, count, flags );
146 
147       if ( FT_ERR_NEQ( error, Unimplemented_Feature ) )
148         return error;
149     }
150 
151     error = FT_Err_Ok;
152 
153     if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
154       return FT_THROW( Unimplemented_Feature );
155 
156     flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
157     factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024;
158     for ( nn = 0; nn < count; nn++ )
159     {
160       error = FT_Load_Glyph( face, start + nn, flags );
161       if ( error )
162         break;
163 
164       /* scale from 26.6 to 16.16, unless NO_SCALE was requested */
165       padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
166                       ? face->glyph->advance.y * factor
167                       : face->glyph->advance.x * factor;
168     }
169 
170     return error;
171   }
172 
173 
174 /* END */
175