1/****************************************************************************
2 *
3 * ftadvanc.c
4 *
5 * Quick computation of advance widths (body).
6 *
7 * Copyright (C) 2008-2023 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
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 )
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 )
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