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