Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / base / ftadvanc.c
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 */