OLD | NEW |
1 /***************************************************************************/ | 1 /***************************************************************************/ |
2 /* */ | 2 /* */ |
3 /* ttgxvar.c */ | 3 /* ttgxvar.c */ |
4 /* */ | 4 /* */ |
5 /* TrueType GX Font Variation loader */ | 5 /* TrueType GX Font Variation loader */ |
6 /* */ | 6 /* */ |
7 /* Copyright 2004-2014 by */ | 7 /* Copyright 2004-2015 by */ |
8 /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ | 8 /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ |
9 /* */ | 9 /* */ |
10 /* This file is part of the FreeType project, and may only be used, */ | 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 */ | 11 /* modified, and distributed under the terms of the FreeType project */ |
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
13 /* this file you indicate that you have read the license and */ | 13 /* this file you indicate that you have read the license and */ |
14 /* understand and accept it fully. */ | 14 /* understand and accept it fully. */ |
15 /* */ | 15 /* */ |
16 /***************************************************************************/ | 16 /***************************************************************************/ |
17 | 17 |
18 | 18 |
19 /*************************************************************************/ | 19 /*************************************************************************/ |
20 /* */ | 20 /* */ |
21 /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ | 21 /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ |
22 /* */ | 22 /* */ |
23 /* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ | 23 /* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fg
ca]var.html */ |
24 /* */ | 24 /* */ |
25 /* The documentation for `fvar' is inconsistent. At one point it says */ | 25 /* The documentation for `fvar' is inconsistent. At one point it says */ |
26 /* that `countSizePairs' should be 3, at another point 2. It should */ | 26 /* that `countSizePairs' should be 3, at another point 2. It should */ |
27 /* be 2. */ | 27 /* be 2. */ |
28 /* */ | 28 /* */ |
29 /* The documentation for `gvar' is not intelligible; `cvar' refers you */ | 29 /* The documentation for `gvar' is not intelligible; `cvar' refers you */ |
30 /* to `gvar' and is thus also incomprehensible. */ | 30 /* to `gvar' and is thus also incomprehensible. */ |
31 /* */ | 31 /* */ |
32 /* The documentation for `avar' appears correct, but Apple has no fonts */ | 32 /* The documentation for `avar' appears correct, but Apple has no fonts */ |
33 /* with an `avar' table, so it is hard to test. */ | 33 /* with an `avar' table, so it is hard to test. */ |
(...skipping 19 matching lines...) Expand all Loading... |
53 | 53 |
54 #include "ttpload.h" | 54 #include "ttpload.h" |
55 #include "ttgxvar.h" | 55 #include "ttgxvar.h" |
56 | 56 |
57 #include "tterrors.h" | 57 #include "tterrors.h" |
58 | 58 |
59 | 59 |
60 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT | 60 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT |
61 | 61 |
62 | 62 |
63 #define FT_Stream_FTell( stream ) \ | 63 #define FT_Stream_FTell( stream ) \ |
64 (FT_ULong)( (stream)->cursor - (stream)->base ) | 64 (FT_ULong)( (stream)->cursor - (stream)->base ) |
65 #define FT_Stream_SeekSet( stream, off ) \ | 65 #define FT_Stream_SeekSet( stream, off ) \ |
66 ( (stream)->cursor = (stream)->base + (off) ) | 66 ( (stream)->cursor = (stream)->base + (off) ) |
67 | 67 |
68 | 68 |
69 /*************************************************************************/ | 69 /*************************************************************************/ |
70 /* */ | 70 /* */ |
71 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | 71 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
72 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | 72 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
73 /* messages during execution. */ | 73 /* messages during execution. */ |
74 /* */ | 74 /* */ |
75 #undef FT_COMPONENT | 75 #undef FT_COMPONENT |
(...skipping 13 matching lines...) Expand all Loading... |
89 /* */ | 89 /* */ |
90 /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ | 90 /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ |
91 /* indicates that there is a delta for every point without needing to */ | 91 /* indicates that there is a delta for every point without needing to */ |
92 /* enumerate all of them. */ | 92 /* enumerate all of them. */ |
93 /* */ | 93 /* */ |
94 | 94 |
95 /* ensure that value `0' has the same width as a pointer */ | 95 /* ensure that value `0' has the same width as a pointer */ |
96 #define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 | 96 #define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 |
97 | 97 |
98 | 98 |
99 #define GX_PT_POINTS_ARE_WORDS 0x80 | 99 #define GX_PT_POINTS_ARE_WORDS 0x80U |
100 #define GX_PT_POINT_RUN_COUNT_MASK 0x7F | 100 #define GX_PT_POINT_RUN_COUNT_MASK 0x7FU |
101 | 101 |
102 | 102 |
103 /*************************************************************************/ | 103 /*************************************************************************/ |
104 /* */ | 104 /* */ |
105 /* <Function> */ | 105 /* <Function> */ |
106 /* ft_var_readpackedpoints */ | 106 /* ft_var_readpackedpoints */ |
107 /* */ | 107 /* */ |
108 /* <Description> */ | 108 /* <Description> */ |
109 /* Read a set of points to which the following deltas will apply. */ | 109 /* Read a set of points to which the following deltas will apply. */ |
110 /* Points are packed with a run length encoding. */ | 110 /* Points are packed with a run length encoding. */ |
111 /* */ | 111 /* */ |
112 /* <Input> */ | 112 /* <Input> */ |
113 /* stream :: The data stream. */ | 113 /* stream :: The data stream. */ |
114 /* */ | 114 /* */ |
115 /* <Output> */ | 115 /* <Output> */ |
116 /* point_cnt :: The number of points read. A zero value means that */ | 116 /* point_cnt :: The number of points read. A zero value means that */ |
117 /* all points in the glyph will be affected, without */ | 117 /* all points in the glyph will be affected, without */ |
118 /* enumerating them individually. */ | 118 /* enumerating them individually. */ |
119 /* */ | 119 /* */ |
120 /* <Return> */ | 120 /* <Return> */ |
121 /* An array of FT_UShort containing the affected points or the */ | 121 /* An array of FT_UShort containing the affected points or the */ |
122 /* special value ALL_POINTS. */ | 122 /* special value ALL_POINTS. */ |
123 /* */ | 123 /* */ |
124 static FT_UShort* | 124 static FT_UShort* |
125 ft_var_readpackedpoints( FT_Stream stream, | 125 ft_var_readpackedpoints( FT_Stream stream, |
126 FT_UInt *point_cnt ) | 126 FT_UInt *point_cnt ) |
127 { | 127 { |
128 FT_UShort *points = NULL; | 128 FT_UShort *points = NULL; |
129 FT_Int n; | 129 FT_UInt n; |
130 FT_Int runcnt; | 130 FT_UInt runcnt; |
131 FT_Int i; | 131 FT_UInt i, j; |
132 FT_Int j; | 132 FT_UShort first; |
133 FT_Int first; | |
134 FT_Memory memory = stream->memory; | 133 FT_Memory memory = stream->memory; |
135 FT_Error error = FT_Err_Ok; | 134 FT_Error error = FT_Err_Ok; |
136 | 135 |
137 FT_UNUSED( error ); | 136 FT_UNUSED( error ); |
138 | 137 |
139 | 138 |
140 *point_cnt = n = FT_GET_BYTE(); | 139 *point_cnt = 0; |
| 140 |
| 141 n = FT_GET_BYTE(); |
141 if ( n == 0 ) | 142 if ( n == 0 ) |
142 return ALL_POINTS; | 143 return ALL_POINTS; |
143 | 144 |
144 if ( n & GX_PT_POINTS_ARE_WORDS ) | 145 if ( n & GX_PT_POINTS_ARE_WORDS ) |
145 n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); | 146 { |
| 147 n &= GX_PT_POINT_RUN_COUNT_MASK; |
| 148 n <<= 8; |
| 149 n |= FT_GET_BYTE(); |
| 150 } |
146 | 151 |
147 if ( FT_NEW_ARRAY( points, n ) ) | 152 if ( FT_NEW_ARRAY( points, n ) ) |
148 return NULL; | 153 return NULL; |
149 | 154 |
| 155 *point_cnt = n; |
| 156 |
150 i = 0; | 157 i = 0; |
151 while ( i < n ) | 158 while ( i < n ) |
152 { | 159 { |
153 runcnt = FT_GET_BYTE(); | 160 runcnt = FT_GET_BYTE(); |
154 if ( runcnt & GX_PT_POINTS_ARE_WORDS ) | 161 if ( runcnt & GX_PT_POINTS_ARE_WORDS ) |
155 { | 162 { |
156 runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; | 163 runcnt &= GX_PT_POINT_RUN_COUNT_MASK; |
157 first = points[i++] = FT_GET_USHORT(); | 164 first = FT_GET_USHORT(); |
| 165 points[i++] = first; |
158 | 166 |
159 if ( runcnt < 1 || i + runcnt >= n ) | 167 if ( runcnt < 1 || i + runcnt > n ) |
160 goto Exit; | 168 goto Exit; |
161 | 169 |
162 /* first point not included in runcount */ | 170 /* first point not included in run count */ |
163 for ( j = 0; j < runcnt; ++j ) | 171 for ( j = 0; j < runcnt; j++ ) |
164 points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); | 172 { |
| 173 first += FT_GET_USHORT(); |
| 174 points[i++] = first; |
| 175 } |
165 } | 176 } |
166 else | 177 else |
167 { | 178 { |
168 first = points[i++] = FT_GET_BYTE(); | 179 first = FT_GET_BYTE(); |
| 180 points[i++] = first; |
169 | 181 |
170 if ( runcnt < 1 || i + runcnt >= n ) | 182 if ( runcnt < 1 || i + runcnt > n ) |
171 goto Exit; | 183 goto Exit; |
172 | 184 |
173 for ( j = 0; j < runcnt; ++j ) | 185 for ( j = 0; j < runcnt; j++ ) |
174 points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); | 186 { |
| 187 first += FT_GET_BYTE(); |
| 188 points[i++] = first; |
| 189 } |
175 } | 190 } |
176 } | 191 } |
177 | 192 |
178 Exit: | 193 Exit: |
179 return points; | 194 return points; |
180 } | 195 } |
181 | 196 |
182 | 197 |
183 enum | 198 #define GX_DT_DELTAS_ARE_ZERO 0x80U |
184 { | 199 #define GX_DT_DELTAS_ARE_WORDS 0x40U |
185 GX_DT_DELTAS_ARE_ZERO = 0x80, | 200 #define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU |
186 GX_DT_DELTAS_ARE_WORDS = 0x40, | |
187 GX_DT_DELTA_RUN_COUNT_MASK = 0x3F | |
188 }; | |
189 | 201 |
190 | 202 |
191 /*************************************************************************/ | 203 /*************************************************************************/ |
192 /* */ | 204 /* */ |
193 /* <Function> */ | 205 /* <Function> */ |
194 /* ft_var_readpackeddeltas */ | 206 /* ft_var_readpackeddeltas */ |
195 /* */ | 207 /* */ |
196 /* <Description> */ | 208 /* <Description> */ |
197 /* Read a set of deltas. These are packed slightly differently than */ | 209 /* Read a set of deltas. These are packed slightly differently than */ |
198 /* points. In particular there is no overall count. */ | 210 /* points. In particular there is no overall count. */ |
199 /* */ | 211 /* */ |
200 /* <Input> */ | 212 /* <Input> */ |
201 /* stream :: The data stream. */ | 213 /* stream :: The data stream. */ |
202 /* */ | 214 /* */ |
203 /* delta_cnt :: The number of to be read. */ | 215 /* delta_cnt :: The number of deltas to be read. */ |
204 /* */ | 216 /* */ |
205 /* <Return> */ | 217 /* <Return> */ |
206 /* An array of FT_Short containing the deltas for the affected */ | 218 /* An array of FT_Short containing the deltas for the affected */ |
207 /* points. (This only gets the deltas for one dimension. It will */ | 219 /* points. (This only gets the deltas for one dimension. It will */ |
208 /* generally be called twice, once for x, once for y. When used in */ | 220 /* generally be called twice, once for x, once for y. When used in */ |
209 /* cvt table, it will only be called once.) */ | 221 /* cvt table, it will only be called once.) */ |
210 /* */ | 222 /* */ |
211 static FT_Short* | 223 static FT_Short* |
212 ft_var_readpackeddeltas( FT_Stream stream, | 224 ft_var_readpackeddeltas( FT_Stream stream, |
213 FT_Offset delta_cnt ) | 225 FT_UInt delta_cnt ) |
214 { | 226 { |
215 FT_Short *deltas = NULL; | 227 FT_Short *deltas = NULL; |
216 FT_UInt runcnt; | 228 FT_UInt runcnt, cnt; |
217 FT_Offset i; | 229 FT_UInt i, j; |
218 FT_UInt j; | |
219 FT_Memory memory = stream->memory; | 230 FT_Memory memory = stream->memory; |
220 FT_Error error = FT_Err_Ok; | 231 FT_Error error = FT_Err_Ok; |
221 | 232 |
222 FT_UNUSED( error ); | 233 FT_UNUSED( error ); |
223 | 234 |
224 | 235 |
225 if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) | 236 if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) |
226 return NULL; | 237 return NULL; |
227 | 238 |
228 i = 0; | 239 i = 0; |
229 while ( i < delta_cnt ) | 240 while ( i < delta_cnt ) |
230 { | 241 { |
231 runcnt = FT_GET_BYTE(); | 242 runcnt = FT_GET_BYTE(); |
| 243 cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; |
| 244 |
232 if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) | 245 if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) |
233 { | 246 { |
234 /* runcnt zeroes get added */ | 247 /* `runcnt' zeroes get added */ |
235 for ( j = 0; | 248 for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
236 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; | |
237 ++j ) | |
238 deltas[i++] = 0; | 249 deltas[i++] = 0; |
239 } | 250 } |
240 else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) | 251 else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) |
241 { | 252 { |
242 /* runcnt shorts from the stack */ | 253 /* `runcnt' shorts from the stack */ |
243 for ( j = 0; | 254 for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
244 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; | |
245 ++j ) | |
246 deltas[i++] = FT_GET_SHORT(); | 255 deltas[i++] = FT_GET_SHORT(); |
247 } | 256 } |
248 else | 257 else |
249 { | 258 { |
250 /* runcnt signed bytes from the stack */ | 259 /* `runcnt' signed bytes from the stack */ |
251 for ( j = 0; | 260 for ( j = 0; j <= cnt && i < delta_cnt; j++ ) |
252 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; | |
253 ++j ) | |
254 deltas[i++] = FT_GET_CHAR(); | 261 deltas[i++] = FT_GET_CHAR(); |
255 } | 262 } |
256 | 263 |
257 if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) | 264 if ( j <= cnt ) |
258 { | 265 { |
259 /* Bad format */ | 266 /* bad format */ |
260 FT_FREE( deltas ); | 267 FT_FREE( deltas ); |
261 return NULL; | 268 return NULL; |
262 } | 269 } |
263 } | 270 } |
264 | 271 |
265 return deltas; | 272 return deltas; |
266 } | 273 } |
267 | 274 |
268 | 275 |
269 /*************************************************************************/ | 276 /*************************************************************************/ |
270 /* */ | 277 /* */ |
271 /* <Function> */ | 278 /* <Function> */ |
272 /* ft_var_load_avar */ | 279 /* ft_var_load_avar */ |
273 /* */ | 280 /* */ |
274 /* <Description> */ | 281 /* <Description> */ |
275 /* Parse the `avar' table if present. It need not be, so we return */ | 282 /* Parse the `avar' table if present. It need not be, so we return */ |
276 /* nothing. */ | 283 /* nothing. */ |
277 /* */ | 284 /* */ |
278 /* <InOut> */ | 285 /* <InOut> */ |
279 /* face :: The font face. */ | 286 /* face :: The font face. */ |
280 /* */ | 287 /* */ |
281 static void | 288 static void |
282 ft_var_load_avar( TT_Face face ) | 289 ft_var_load_avar( TT_Face face ) |
283 { | 290 { |
284 FT_Stream stream = FT_FACE_STREAM(face); | 291 FT_Stream stream = FT_FACE_STREAM( face ); |
285 FT_Memory memory = stream->memory; | 292 FT_Memory memory = stream->memory; |
286 GX_Blend blend = face->blend; | 293 GX_Blend blend = face->blend; |
287 GX_AVarSegment segment; | 294 GX_AVarSegment segment; |
288 FT_Error error = FT_Err_Ok; | 295 FT_Error error = FT_Err_Ok; |
289 FT_ULong version; | 296 FT_Long version; |
290 FT_Long axisCount; | 297 FT_Long axisCount; |
291 FT_Int i, j; | 298 FT_Int i, j; |
292 FT_ULong table_len; | 299 FT_ULong table_len; |
293 | 300 |
294 FT_UNUSED( error ); | 301 FT_UNUSED( error ); |
295 | 302 |
296 | 303 |
| 304 FT_TRACE2(( "AVAR " )); |
| 305 |
297 blend->avar_checked = TRUE; | 306 blend->avar_checked = TRUE; |
298 if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0
) | 307 error = face->goto_table( face, TTAG_avar, stream, &table_len ); |
| 308 if ( error ) |
| 309 { |
| 310 FT_TRACE2(( "is missing\n" )); |
299 return; | 311 return; |
| 312 } |
300 | 313 |
301 if ( FT_FRAME_ENTER( table_len ) ) | 314 if ( FT_FRAME_ENTER( table_len ) ) |
302 return; | 315 return; |
303 | 316 |
304 version = FT_GET_LONG(); | 317 version = FT_GET_LONG(); |
305 axisCount = FT_GET_LONG(); | 318 axisCount = FT_GET_LONG(); |
306 | 319 |
307 if ( version != 0x00010000L || | 320 if ( version != 0x00010000L ) |
308 axisCount != (FT_Long)blend->mmvar->num_axis ) | 321 { |
| 322 FT_TRACE2(( "bad table version\n" )); |
309 goto Exit; | 323 goto Exit; |
| 324 } |
| 325 |
| 326 FT_TRACE2(( "loaded\n" )); |
| 327 |
| 328 if ( axisCount != (FT_Long)blend->mmvar->num_axis ) |
| 329 { |
| 330 FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `cvar'\n" |
| 331 " table are different\n" )); |
| 332 goto Exit; |
| 333 } |
310 | 334 |
311 if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) | 335 if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) |
312 goto Exit; | 336 goto Exit; |
313 | 337 |
314 segment = &blend->avar_segment[0]; | 338 segment = &blend->avar_segment[0]; |
315 for ( i = 0; i < axisCount; ++i, ++segment ) | 339 for ( i = 0; i < axisCount; i++, segment++ ) |
316 { | 340 { |
| 341 FT_TRACE5(( " axis %d:\n", i )); |
| 342 |
317 segment->pairCount = FT_GET_USHORT(); | 343 segment->pairCount = FT_GET_USHORT(); |
318 if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) | 344 if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) |
319 { | 345 { |
320 /* Failure. Free everything we have done so far. We must do */ | 346 /* Failure. Free everything we have done so far. We must do */ |
321 /* it right now since loading the `avar' table is optional. */ | 347 /* it right now since loading the `avar' table is optional. */ |
322 | 348 |
323 for ( j = i - 1; j >= 0; --j ) | 349 for ( j = i - 1; j >= 0; j-- ) |
324 FT_FREE( blend->avar_segment[j].correspondence ); | 350 FT_FREE( blend->avar_segment[j].correspondence ); |
325 | 351 |
326 FT_FREE( blend->avar_segment ); | 352 FT_FREE( blend->avar_segment ); |
327 blend->avar_segment = NULL; | 353 blend->avar_segment = NULL; |
328 goto Exit; | 354 goto Exit; |
329 } | 355 } |
330 | 356 |
331 for ( j = 0; j < segment->pairCount; ++j ) | 357 for ( j = 0; j < segment->pairCount; j++ ) |
332 { | 358 { |
333 segment->correspondence[j].fromCoord = | 359 /* convert to Fixed */ |
334 FT_GET_SHORT() << 2; /* convert to Fixed */ | 360 segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4; |
335 segment->correspondence[j].toCoord = | 361 segment->correspondence[j].toCoord = FT_GET_SHORT() * 4; |
336 FT_GET_SHORT()<<2; /* convert to Fixed */ | 362 |
| 363 FT_TRACE5(( " mapping %.4f to %.4f\n", |
| 364 segment->correspondence[j].fromCoord / 65536.0, |
| 365 segment->correspondence[j].toCoord / 65536.0 )); |
337 } | 366 } |
| 367 |
| 368 FT_TRACE5(( "\n" )); |
338 } | 369 } |
339 | 370 |
340 Exit: | 371 Exit: |
341 FT_FRAME_EXIT(); | 372 FT_FRAME_EXIT(); |
342 } | 373 } |
343 | 374 |
344 | 375 |
345 typedef struct GX_GVar_Head_ | 376 typedef struct GX_GVar_Head_ |
346 { | 377 { |
347 FT_Long version; | 378 FT_Long version; |
348 FT_UShort axisCount; | 379 FT_UShort axisCount; |
349 FT_UShort globalCoordCount; | 380 FT_UShort globalCoordCount; |
350 FT_ULong offsetToCoord; | 381 FT_ULong offsetToCoord; |
351 FT_UShort glyphCount; | 382 FT_UShort glyphCount; |
352 FT_UShort flags; | 383 FT_UShort flags; |
353 FT_ULong offsetToData; | 384 FT_ULong offsetToData; |
354 | 385 |
355 } GX_GVar_Head; | 386 } GX_GVar_Head; |
356 | 387 |
357 | 388 |
358 /*************************************************************************/ | 389 /*************************************************************************/ |
359 /* */ | 390 /* */ |
360 /* <Function> */ | 391 /* <Function> */ |
361 /* ft_var_load_gvar */ | 392 /* ft_var_load_gvar */ |
362 /* */ | 393 /* */ |
363 /* <Description> */ | 394 /* <Description> */ |
364 /* Parses the `gvar' table if present. If `fvar' is there, `gvar' */ | 395 /* Parse the `gvar' table if present. If `fvar' is there, `gvar' had */ |
365 /* had better be there too. */ | 396 /* better be there too. */ |
366 /* */ | 397 /* */ |
367 /* <InOut> */ | 398 /* <InOut> */ |
368 /* face :: The font face. */ | 399 /* face :: The font face. */ |
369 /* */ | 400 /* */ |
370 /* <Return> */ | 401 /* <Return> */ |
371 /* FreeType error code. 0 means success. */ | 402 /* FreeType error code. 0 means success. */ |
372 /* */ | 403 /* */ |
373 static FT_Error | 404 static FT_Error |
374 ft_var_load_gvar( TT_Face face ) | 405 ft_var_load_gvar( TT_Face face ) |
375 { | 406 { |
376 FT_Stream stream = FT_FACE_STREAM(face); | 407 FT_Stream stream = FT_FACE_STREAM( face ); |
377 FT_Memory memory = stream->memory; | 408 FT_Memory memory = stream->memory; |
378 GX_Blend blend = face->blend; | 409 GX_Blend blend = face->blend; |
379 FT_Error error; | 410 FT_Error error; |
380 FT_UInt i, j; | 411 FT_UInt i, j; |
381 FT_ULong table_len; | 412 FT_ULong table_len; |
382 FT_ULong gvar_start; | 413 FT_ULong gvar_start; |
383 FT_ULong offsetToData; | 414 FT_ULong offsetToData; |
384 GX_GVar_Head gvar_head; | 415 GX_GVar_Head gvar_head; |
385 | 416 |
386 static const FT_Frame_Field gvar_fields[] = | 417 static const FT_Frame_Field gvar_fields[] = |
387 { | 418 { |
388 | 419 |
389 #undef FT_STRUCTURE | 420 #undef FT_STRUCTURE |
390 #define FT_STRUCTURE GX_GVar_Head | 421 #define FT_STRUCTURE GX_GVar_Head |
391 | 422 |
392 FT_FRAME_START( 20 ), | 423 FT_FRAME_START( 20 ), |
393 FT_FRAME_LONG ( version ), | 424 FT_FRAME_LONG ( version ), |
394 FT_FRAME_USHORT( axisCount ), | 425 FT_FRAME_USHORT( axisCount ), |
395 FT_FRAME_USHORT( globalCoordCount ), | 426 FT_FRAME_USHORT( globalCoordCount ), |
396 FT_FRAME_ULONG ( offsetToCoord ), | 427 FT_FRAME_ULONG ( offsetToCoord ), |
397 FT_FRAME_USHORT( glyphCount ), | 428 FT_FRAME_USHORT( glyphCount ), |
398 FT_FRAME_USHORT( flags ), | 429 FT_FRAME_USHORT( flags ), |
399 FT_FRAME_ULONG ( offsetToData ), | 430 FT_FRAME_ULONG ( offsetToData ), |
400 FT_FRAME_END | 431 FT_FRAME_END |
401 }; | 432 }; |
402 | 433 |
403 if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0
) | 434 |
| 435 FT_TRACE2(( "GVAR " )); |
| 436 |
| 437 if ( ( error = face->goto_table( face, |
| 438 TTAG_gvar, |
| 439 stream, |
| 440 &table_len ) ) != 0 ) |
| 441 { |
| 442 FT_TRACE2(( "is missing\n" )); |
404 goto Exit; | 443 goto Exit; |
| 444 } |
405 | 445 |
406 gvar_start = FT_STREAM_POS( ); | 446 gvar_start = FT_STREAM_POS( ); |
407 if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) | 447 if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) |
408 goto Exit; | 448 goto Exit; |
409 | 449 |
410 blend->tuplecount = gvar_head.globalCoordCount; | 450 blend->tuplecount = gvar_head.globalCoordCount; |
411 blend->gv_glyphcnt = gvar_head.glyphCount; | 451 blend->gv_glyphcnt = gvar_head.glyphCount; |
412 offsetToData = gvar_start + gvar_head.offsetToData; | 452 offsetToData = gvar_start + gvar_head.offsetToData; |
413 | 453 |
414 if ( gvar_head.version != (FT_Long)0x00010000L || | 454 if ( gvar_head.version != 0x00010000L ) |
415 gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) | |
416 { | 455 { |
| 456 FT_TRACE1(( "bad table version\n" )); |
417 error = FT_THROW( Invalid_Table ); | 457 error = FT_THROW( Invalid_Table ); |
418 goto Exit; | 458 goto Exit; |
419 } | 459 } |
420 | 460 |
| 461 FT_TRACE2(( "loaded\n" )); |
| 462 |
| 463 if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) |
| 464 { |
| 465 FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" |
| 466 " table are different\n" )); |
| 467 error = FT_THROW( Invalid_Table ); |
| 468 goto Exit; |
| 469 } |
| 470 |
| 471 FT_TRACE5(( "gvar: there are %d shared coordinates:\n", |
| 472 blend->tuplecount )); |
| 473 |
421 if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) | 474 if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) |
422 goto Exit; | 475 goto Exit; |
423 | 476 |
424 if ( gvar_head.flags & 1 ) | 477 if ( gvar_head.flags & 1 ) |
425 { | 478 { |
426 /* long offsets (one more offset than glyphs, to mark size of last) */ | 479 /* long offsets (one more offset than glyphs, to mark size of last) */ |
427 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) | 480 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) |
428 goto Exit; | 481 goto Exit; |
429 | 482 |
430 for ( i = 0; i <= blend->gv_glyphcnt; ++i ) | 483 for ( i = 0; i <= blend->gv_glyphcnt; i++ ) |
431 blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); | 484 blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); |
432 | 485 |
433 FT_FRAME_EXIT(); | 486 FT_FRAME_EXIT(); |
434 } | 487 } |
435 else | 488 else |
436 { | 489 { |
437 /* short offsets (one more offset than glyphs, to mark size of last) */ | 490 /* short offsets (one more offset than glyphs, to mark size of last) */ |
438 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) | 491 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) |
439 goto Exit; | 492 goto Exit; |
440 | 493 |
441 for ( i = 0; i <= blend->gv_glyphcnt; ++i ) | 494 for ( i = 0; i <= blend->gv_glyphcnt; i++ ) |
442 blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; | 495 blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; |
443 /* XXX: Undocumented: `*2'! */ | 496 /* XXX: Undocumented: `*2'! */ |
444 | 497 |
445 FT_FRAME_EXIT(); | 498 FT_FRAME_EXIT(); |
446 } | 499 } |
447 | 500 |
448 if ( blend->tuplecount != 0 ) | 501 if ( blend->tuplecount != 0 ) |
449 { | 502 { |
450 if ( FT_NEW_ARRAY( blend->tuplecoords, | 503 if ( FT_NEW_ARRAY( blend->tuplecoords, |
451 gvar_head.axisCount * blend->tuplecount ) ) | 504 gvar_head.axisCount * blend->tuplecount ) ) |
452 goto Exit; | 505 goto Exit; |
453 | 506 |
454 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || | 507 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || |
455 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L )
) | 508 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) |
456 goto Exit; | 509 goto Exit; |
457 | 510 |
458 for ( i = 0; i < blend->tuplecount; ++i ) | 511 for ( i = 0; i < blend->tuplecount; i++ ) |
459 for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) | 512 { |
| 513 FT_TRACE5(( " [ " )); |
| 514 for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; j++ ) |
| 515 { |
460 blend->tuplecoords[i * gvar_head.axisCount + j] = | 516 blend->tuplecoords[i * gvar_head.axisCount + j] = |
461 FT_GET_SHORT() << 2; /* convert to FT_Fixed */ | 517 FT_GET_SHORT() * 4; /* convert to FT_Fixed */ |
| 518 FT_TRACE5(( "%.4f ", |
| 519 blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); |
| 520 } |
| 521 FT_TRACE5(( "]\n" )); |
| 522 } |
| 523 |
| 524 FT_TRACE5(( "\n" )); |
462 | 525 |
463 FT_FRAME_EXIT(); | 526 FT_FRAME_EXIT(); |
464 } | 527 } |
465 | 528 |
466 Exit: | 529 Exit: |
467 return error; | 530 return error; |
468 } | 531 } |
469 | 532 |
470 | 533 |
471 /*************************************************************************/ | 534 /*************************************************************************/ |
(...skipping 27 matching lines...) Expand all Loading... |
499 ft_var_apply_tuple( GX_Blend blend, | 562 ft_var_apply_tuple( GX_Blend blend, |
500 FT_UShort tupleIndex, | 563 FT_UShort tupleIndex, |
501 FT_Fixed* tuple_coords, | 564 FT_Fixed* tuple_coords, |
502 FT_Fixed* im_start_coords, | 565 FT_Fixed* im_start_coords, |
503 FT_Fixed* im_end_coords ) | 566 FT_Fixed* im_end_coords ) |
504 { | 567 { |
505 FT_UInt i; | 568 FT_UInt i; |
506 FT_Fixed apply = 0x10000L; | 569 FT_Fixed apply = 0x10000L; |
507 | 570 |
508 | 571 |
509 for ( i = 0; i < blend->num_axis; ++i ) | 572 for ( i = 0; i < blend->num_axis; i++ ) |
510 { | 573 { |
| 574 FT_TRACE6(( " axis coordinate %d (%.4f):\n", |
| 575 i, blend->normalizedcoords[i] / 65536.0 )); |
| 576 |
| 577 /* It's not clear why (for intermediate tuples) we don't need */ |
| 578 /* to check against start/end -- the documentation says we don't. */ |
| 579 /* Similarly, it's unclear why we don't need to scale along the */ |
| 580 /* axis. */ |
| 581 |
511 if ( tuple_coords[i] == 0 ) | 582 if ( tuple_coords[i] == 0 ) |
512 /* It's not clear why (for intermediate tuples) we don't need */ | 583 { |
513 /* to check against start/end -- the documentation says we don't. */ | 584 FT_TRACE6(( " tuple coordinate is zero, ignored\n", i )); |
514 /* Similarly, it's unclear why we don't need to scale along the */ | |
515 /* axis. */ | |
516 continue; | 585 continue; |
| 586 } |
517 | 587 |
518 else if ( blend->normalizedcoords[i] == 0 || | 588 else if ( blend->normalizedcoords[i] == 0 ) |
519 ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || | 589 { |
| 590 FT_TRACE6(( " axis coordinate is zero, stop\n" )); |
| 591 apply = 0; |
| 592 break; |
| 593 } |
| 594 |
| 595 else if ( ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || |
520 ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) | 596 ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) |
521 { | 597 { |
| 598 FT_TRACE6(( " tuple coordinate value %.4f is exceeded, stop\n", |
| 599 tuple_coords[i] / 65536.0 )); |
522 apply = 0; | 600 apply = 0; |
523 break; | 601 break; |
524 } | 602 } |
525 | 603 |
526 else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) | 604 else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) |
| 605 { |
| 606 FT_TRACE6(( " tuple coordinate value %.4f fits\n", |
| 607 tuple_coords[i] / 65536.0 )); |
527 /* not an intermediate tuple */ | 608 /* not an intermediate tuple */ |
528 apply = FT_MulFix( apply, | 609 apply = FT_MulFix( apply, |
529 blend->normalizedcoords[i] > 0 | 610 blend->normalizedcoords[i] > 0 |
530 ? blend->normalizedcoords[i] | 611 ? blend->normalizedcoords[i] |
531 : -blend->normalizedcoords[i] ); | 612 : -blend->normalizedcoords[i] ); |
| 613 } |
532 | 614 |
533 else if ( blend->normalizedcoords[i] <= im_start_coords[i] || | 615 else if ( blend->normalizedcoords[i] < im_start_coords[i] || |
534 blend->normalizedcoords[i] >= im_end_coords[i] ) | 616 blend->normalizedcoords[i] > im_end_coords[i] ) |
535 { | 617 { |
| 618 FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] is exceeded," |
| 619 " stop\n", |
| 620 im_start_coords[i] / 65536.0, |
| 621 im_end_coords[i] / 65536.0 )); |
536 apply = 0; | 622 apply = 0; |
537 break; | 623 break; |
538 } | 624 } |
539 | 625 |
540 else if ( blend->normalizedcoords[i] < tuple_coords[i] ) | 626 else if ( blend->normalizedcoords[i] < tuple_coords[i] ) |
| 627 { |
| 628 FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", |
| 629 im_start_coords[i] / 65536.0, |
| 630 im_end_coords[i] / 65536.0 )); |
541 apply = FT_MulDiv( apply, | 631 apply = FT_MulDiv( apply, |
542 blend->normalizedcoords[i] - im_start_coords[i], | 632 blend->normalizedcoords[i] - im_start_coords[i], |
543 tuple_coords[i] - im_start_coords[i] ); | 633 tuple_coords[i] - im_start_coords[i] ); |
| 634 } |
544 | 635 |
545 else | 636 else |
| 637 { |
| 638 FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", |
| 639 im_start_coords[i] / 65536.0, |
| 640 im_end_coords[i] / 65536.0 )); |
546 apply = FT_MulDiv( apply, | 641 apply = FT_MulDiv( apply, |
547 im_end_coords[i] - blend->normalizedcoords[i], | 642 im_end_coords[i] - blend->normalizedcoords[i], |
548 im_end_coords[i] - tuple_coords[i] ); | 643 im_end_coords[i] - tuple_coords[i] ); |
| 644 } |
549 } | 645 } |
550 | 646 |
| 647 FT_TRACE6(( " apply factor is %.4f\n", apply / 65536.0 )); |
| 648 |
551 return apply; | 649 return apply; |
552 } | 650 } |
553 | 651 |
554 | 652 |
555 /*************************************************************************/ | 653 /*************************************************************************/ |
556 /*************************************************************************/ | 654 /*************************************************************************/ |
557 /***** *****/ | 655 /***** *****/ |
558 /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ | 656 /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ |
559 /***** *****/ | 657 /***** *****/ |
560 /*************************************************************************/ | 658 /*************************************************************************/ |
561 /*************************************************************************/ | 659 /*************************************************************************/ |
562 | 660 |
563 | 661 |
564 typedef struct GX_FVar_Head_ | 662 typedef struct GX_FVar_Head_ |
565 { | 663 { |
566 FT_Long version; | 664 FT_Long version; |
567 FT_UShort offsetToData; | 665 FT_UShort offsetToData; |
568 FT_UShort countSizePairs; | 666 FT_UShort countSizePairs; |
569 FT_UShort axisCount; | 667 FT_UShort axisCount; |
570 FT_UShort axisSize; | 668 FT_UShort axisSize; |
571 FT_UShort instanceCount; | 669 FT_UShort instanceCount; |
572 FT_UShort instanceSize; | 670 FT_UShort instanceSize; |
573 | 671 |
574 } GX_FVar_Head; | 672 } GX_FVar_Head; |
575 | 673 |
576 | 674 |
577 typedef struct fvar_axis_ | 675 typedef struct fvar_axis_ |
578 { | 676 { |
579 FT_ULong axisTag; | 677 FT_ULong axisTag; |
580 FT_ULong minValue; | 678 FT_Fixed minValue; |
581 FT_ULong defaultValue; | 679 FT_Fixed defaultValue; |
582 FT_ULong maxValue; | 680 FT_Fixed maxValue; |
583 FT_UShort flags; | 681 FT_UShort flags; |
584 FT_UShort nameID; | 682 FT_UShort nameID; |
585 | 683 |
586 } GX_FVar_Axis; | 684 } GX_FVar_Axis; |
587 | 685 |
588 | 686 |
589 /*************************************************************************/ | 687 /*************************************************************************/ |
590 /* */ | 688 /* */ |
591 /* <Function> */ | 689 /* <Function> */ |
592 /* TT_Get_MM_Var */ | 690 /* TT_Get_MM_Var */ |
593 /* */ | 691 /* */ |
594 /* <Description> */ | 692 /* <Description> */ |
595 /* Check that the font's `fvar' table is valid, parse it, and return */ | 693 /* Check that the font's `fvar' table is valid, parse it, and return */ |
596 /* those data. */ | 694 /* those data. */ |
597 /* */ | 695 /* */ |
598 /* <InOut> */ | 696 /* <InOut> */ |
599 /* face :: The font face. */ | 697 /* face :: The font face. */ |
600 /* TT_Get_MM_Var initializes the blend structure. */ | 698 /* TT_Get_MM_Var initializes the blend structure. */ |
601 /* */ | 699 /* */ |
602 /* <Output> */ | 700 /* <Output> */ |
603 /* master :: The `fvar' data (must be freed by caller). */ | 701 /* master :: The `fvar' data (must be freed by caller). Can be NULL, */ |
| 702 /* which makes this function simply load MM support. */ |
604 /* */ | 703 /* */ |
605 /* <Return> */ | 704 /* <Return> */ |
606 /* FreeType error code. 0 means success. */ | 705 /* FreeType error code. 0 means success. */ |
607 /* */ | 706 /* */ |
608 FT_LOCAL_DEF( FT_Error ) | 707 FT_LOCAL_DEF( FT_Error ) |
609 TT_Get_MM_Var( TT_Face face, | 708 TT_Get_MM_Var( TT_Face face, |
610 FT_MM_Var* *master ) | 709 FT_MM_Var* *master ) |
611 { | 710 { |
612 FT_Stream stream = face->root.stream; | 711 FT_Stream stream = face->root.stream; |
613 FT_Memory memory = face->root.memory; | 712 FT_Memory memory = face->root.memory; |
(...skipping 26 matching lines...) Expand all Loading... |
640 }; | 739 }; |
641 | 740 |
642 static const FT_Frame_Field fvaraxis_fields[] = | 741 static const FT_Frame_Field fvaraxis_fields[] = |
643 { | 742 { |
644 | 743 |
645 #undef FT_STRUCTURE | 744 #undef FT_STRUCTURE |
646 #define FT_STRUCTURE GX_FVar_Axis | 745 #define FT_STRUCTURE GX_FVar_Axis |
647 | 746 |
648 FT_FRAME_START( 20 ), | 747 FT_FRAME_START( 20 ), |
649 FT_FRAME_ULONG ( axisTag ), | 748 FT_FRAME_ULONG ( axisTag ), |
650 FT_FRAME_ULONG ( minValue ), | 749 FT_FRAME_LONG ( minValue ), |
651 FT_FRAME_ULONG ( defaultValue ), | 750 FT_FRAME_LONG ( defaultValue ), |
652 FT_FRAME_ULONG ( maxValue ), | 751 FT_FRAME_LONG ( maxValue ), |
653 FT_FRAME_USHORT( flags ), | 752 FT_FRAME_USHORT( flags ), |
654 FT_FRAME_USHORT( nameID ), | 753 FT_FRAME_USHORT( nameID ), |
655 FT_FRAME_END | 754 FT_FRAME_END |
656 }; | 755 }; |
657 | 756 |
658 | 757 |
| 758 /* read the font data and set up the internal representation */ |
| 759 /* if not already done */ |
| 760 |
659 if ( face->blend == NULL ) | 761 if ( face->blend == NULL ) |
660 { | 762 { |
| 763 FT_TRACE2(( "FVAR " )); |
| 764 |
661 /* both `fvar' and `gvar' must be present */ | 765 /* both `fvar' and `gvar' must be present */ |
662 if ( (error = face->goto_table( face, TTAG_gvar, | 766 if ( ( error = face->goto_table( face, TTAG_gvar, |
663 stream, &table_len )) != 0 ) | 767 stream, &table_len ) ) != 0 ) |
| 768 { |
| 769 FT_TRACE1(( "\n" |
| 770 "TT_Get_MM_Var: `gvar' table is missing\n" )); |
664 goto Exit; | 771 goto Exit; |
| 772 } |
665 | 773 |
666 if ( (error = face->goto_table( face, TTAG_fvar, | 774 if ( ( error = face->goto_table( face, TTAG_fvar, |
667 stream, &table_len )) != 0 ) | 775 stream, &table_len ) ) != 0 ) |
| 776 { |
| 777 FT_TRACE1(( "is missing\n" )); |
668 goto Exit; | 778 goto Exit; |
| 779 } |
669 | 780 |
670 fvar_start = FT_STREAM_POS( ); | 781 fvar_start = FT_STREAM_POS( ); |
671 | 782 |
672 if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) | 783 if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) |
673 goto Exit; | 784 goto Exit; |
674 | 785 |
675 if ( fvar_head.version != (FT_Long)0x00010000L || | 786 if ( fvar_head.version != (FT_Long)0x00010000L || |
| 787 #if 0 |
| 788 /* fonts like `JamRegular.ttf' have an incorrect value for */ |
| 789 /* `countSizePairs'; since value 2 is hard-coded in `fvar' */ |
| 790 /* version 1.0, we simply ignore it */ |
676 fvar_head.countSizePairs != 2 || | 791 fvar_head.countSizePairs != 2 || |
| 792 #endif |
677 fvar_head.axisSize != 20 || | 793 fvar_head.axisSize != 20 || |
678 /* axisCount limit implied by 16-bit instanceSize */ | 794 /* axisCount limit implied by 16-bit instanceSize */ |
679 fvar_head.axisCount > 0x3FFE || | 795 fvar_head.axisCount > 0x3FFE || |
680 fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || | 796 fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || |
681 /* instanceCount limit implied by limited range of name IDs */ | 797 /* instanceCount limit implied by limited range of name IDs */ |
682 fvar_head.instanceCount > 0x7EFF || | 798 fvar_head.instanceCount > 0x7EFF || |
683 fvar_head.offsetToData + fvar_head.axisCount * 20U + | 799 fvar_head.offsetToData + fvar_head.axisCount * 20U + |
684 fvar_head.instanceCount * fvar_head.instanceSize > table_len ) | 800 fvar_head.instanceCount * fvar_head.instanceSize > table_len ) |
685 { | 801 { |
| 802 FT_TRACE1(( "\n" |
| 803 "TT_Get_MM_Var: invalid `fvar' header\n" )); |
686 error = FT_THROW( Invalid_Table ); | 804 error = FT_THROW( Invalid_Table ); |
687 goto Exit; | 805 goto Exit; |
688 } | 806 } |
689 | 807 |
| 808 FT_TRACE2(( "loaded\n" )); |
| 809 |
| 810 FT_TRACE5(( "number of GX style axes: %d\n", fvar_head.axisCount )); |
| 811 |
690 if ( FT_NEW( face->blend ) ) | 812 if ( FT_NEW( face->blend ) ) |
691 goto Exit; | 813 goto Exit; |
692 | 814 |
693 /* cannot overflow 32-bit arithmetic because of limits above */ | 815 /* cannot overflow 32-bit arithmetic because of limits above */ |
694 face->blend->mmvar_len = | 816 face->blend->mmvar_len = |
695 sizeof ( FT_MM_Var ) + | 817 sizeof ( FT_MM_Var ) + |
696 fvar_head.axisCount * sizeof ( FT_Var_Axis ) + | 818 fvar_head.axisCount * sizeof ( FT_Var_Axis ) + |
697 fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + | 819 fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + |
698 fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + | 820 fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + |
699 5 * fvar_head.axisCount; | 821 5 * fvar_head.axisCount; |
700 | 822 |
701 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) | 823 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) |
702 goto Exit; | 824 goto Exit; |
703 face->blend->mmvar = mmvar; | 825 face->blend->mmvar = mmvar; |
704 | 826 |
| 827 /* set up pointers and offsets into the `mmvar' array; */ |
| 828 /* the data gets filled in later on */ |
| 829 |
705 mmvar->num_axis = | 830 mmvar->num_axis = |
706 fvar_head.axisCount; | 831 fvar_head.axisCount; |
707 mmvar->num_designs = | 832 mmvar->num_designs = |
708 ~0U; /* meaningless in this context; each glyph */ | 833 ~0U; /* meaningless in this context; each glyph */ |
709 /* may have a different number of designs */ | 834 /* may have a different number of designs */ |
710 /* (or tuples, as called by Apple) */ | 835 /* (or tuples, as called by Apple) */ |
711 mmvar->num_namedstyles = | 836 mmvar->num_namedstyles = |
712 fvar_head.instanceCount; | 837 fvar_head.instanceCount; |
713 mmvar->axis = | 838 mmvar->axis = |
714 (FT_Var_Axis*)&(mmvar[1]); | 839 (FT_Var_Axis*)&( mmvar[1] ); |
715 mmvar->namedstyle = | 840 mmvar->namedstyle = |
716 (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); | 841 (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] ); |
717 | 842 |
718 next_coords = | 843 next_coords = |
719 (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); | 844 (FT_Fixed*)&( mmvar->namedstyle[fvar_head.instanceCount] ); |
720 for ( i = 0; i < fvar_head.instanceCount; ++i ) | 845 for ( i = 0; i < fvar_head.instanceCount; i++ ) |
721 { | 846 { |
722 mmvar->namedstyle[i].coords = next_coords; | 847 mmvar->namedstyle[i].coords = next_coords; |
723 next_coords += fvar_head.axisCount; | 848 next_coords += fvar_head.axisCount; |
724 } | 849 } |
725 | 850 |
726 next_name = (FT_String*)next_coords; | 851 next_name = (FT_String*)next_coords; |
727 for ( i = 0; i < fvar_head.axisCount; ++i ) | 852 for ( i = 0; i < fvar_head.axisCount; i++ ) |
728 { | 853 { |
729 mmvar->axis[i].name = next_name; | 854 mmvar->axis[i].name = next_name; |
730 next_name += 5; | 855 next_name += 5; |
731 } | 856 } |
732 | 857 |
| 858 /* now fill in the data */ |
| 859 |
733 if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) | 860 if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) |
734 goto Exit; | 861 goto Exit; |
735 | 862 |
736 a = mmvar->axis; | 863 a = mmvar->axis; |
737 for ( i = 0; i < fvar_head.axisCount; ++i ) | 864 for ( i = 0; i < fvar_head.axisCount; i++ ) |
738 { | 865 { |
739 GX_FVar_Axis axis_rec; | 866 GX_FVar_Axis axis_rec; |
740 | 867 |
741 | 868 |
742 if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) | 869 if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) |
743 goto Exit; | 870 goto Exit; |
744 a->tag = axis_rec.axisTag; | 871 a->tag = axis_rec.axisTag; |
745 a->minimum = axis_rec.minValue; /* A Fixed */ | 872 a->minimum = axis_rec.minValue; |
746 a->def = axis_rec.defaultValue; /* A Fixed */ | 873 a->def = axis_rec.defaultValue; |
747 a->maximum = axis_rec.maxValue; /* A Fixed */ | 874 a->maximum = axis_rec.maxValue; |
748 a->strid = axis_rec.nameID; | 875 a->strid = axis_rec.nameID; |
749 | 876 |
750 a->name[0] = (FT_String)( a->tag >> 24 ); | 877 a->name[0] = (FT_String)( a->tag >> 24 ); |
751 a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); | 878 a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); |
752 a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); | 879 a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); |
753 a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); | 880 a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); |
754 a->name[4] = 0; | 881 a->name[4] = '\0'; |
755 | 882 |
756 ++a; | 883 FT_TRACE5(( " \"%s\": minimum=%.4f, default=%.4f, maximum=%.4f\n", |
| 884 a->name, |
| 885 a->minimum / 65536.0, |
| 886 a->def / 65536.0, |
| 887 a->maximum / 65536.0 )); |
| 888 |
| 889 a++; |
757 } | 890 } |
758 | 891 |
| 892 FT_TRACE5(( "\n" )); |
| 893 |
759 ns = mmvar->namedstyle; | 894 ns = mmvar->namedstyle; |
760 for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns ) | 895 for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) |
761 { | 896 { |
762 if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) | 897 if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) |
763 goto Exit; | 898 goto Exit; |
764 | 899 |
765 ns->strid = FT_GET_USHORT(); | 900 ns->strid = FT_GET_USHORT(); |
766 (void) /* flags = */ FT_GET_USHORT(); | 901 (void) /* flags = */ FT_GET_USHORT(); |
767 | 902 |
768 for ( j = 0; j < fvar_head.axisCount; ++j ) | 903 for ( j = 0; j < fvar_head.axisCount; j++ ) |
769 ns->coords[j] = FT_GET_ULONG(); /* A Fixed */ | 904 ns->coords[j] = FT_GET_LONG(); |
770 | 905 |
771 FT_FRAME_EXIT(); | 906 FT_FRAME_EXIT(); |
772 } | 907 } |
773 } | 908 } |
774 | 909 |
| 910 /* fill the output array if requested */ |
| 911 |
775 if ( master != NULL ) | 912 if ( master != NULL ) |
776 { | 913 { |
777 FT_UInt n; | 914 FT_UInt n; |
778 | 915 |
779 | 916 |
780 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) | 917 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) |
781 goto Exit; | 918 goto Exit; |
782 FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); | 919 FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); |
783 | 920 |
784 mmvar->axis = | 921 mmvar->axis = |
785 (FT_Var_Axis*)&(mmvar[1]); | 922 (FT_Var_Axis*)&( mmvar[1] ); |
786 mmvar->namedstyle = | 923 mmvar->namedstyle = |
787 (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); | 924 (FT_Var_Named_Style*)&( mmvar->axis[mmvar->num_axis] ); |
788 next_coords = | 925 next_coords = |
789 (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); | 926 (FT_Fixed*)&( mmvar->namedstyle[mmvar->num_namedstyles] ); |
790 | 927 |
791 for ( n = 0; n < mmvar->num_namedstyles; ++n ) | 928 for ( n = 0; n < mmvar->num_namedstyles; n++ ) |
792 { | 929 { |
793 mmvar->namedstyle[n].coords = next_coords; | 930 mmvar->namedstyle[n].coords = next_coords; |
794 next_coords += mmvar->num_axis; | 931 next_coords += mmvar->num_axis; |
795 } | 932 } |
796 | 933 |
797 a = mmvar->axis; | 934 a = mmvar->axis; |
798 next_name = (FT_String*)next_coords; | 935 next_name = (FT_String*)next_coords; |
799 for ( n = 0; n < mmvar->num_axis; ++n ) | 936 for ( n = 0; n < mmvar->num_axis; n++ ) |
800 { | 937 { |
801 a->name = next_name; | 938 a->name = next_name; |
802 | 939 |
803 /* standard PostScript names for some standard apple tags */ | 940 /* standard PostScript names for some standard apple tags */ |
804 if ( a->tag == TTAG_wght ) | 941 if ( a->tag == TTAG_wght ) |
805 a->name = (char *)"Weight"; | 942 a->name = (char*)"Weight"; |
806 else if ( a->tag == TTAG_wdth ) | 943 else if ( a->tag == TTAG_wdth ) |
807 a->name = (char *)"Width"; | 944 a->name = (char*)"Width"; |
808 else if ( a->tag == TTAG_opsz ) | 945 else if ( a->tag == TTAG_opsz ) |
809 a->name = (char *)"OpticalSize"; | 946 a->name = (char*)"OpticalSize"; |
810 else if ( a->tag == TTAG_slnt ) | 947 else if ( a->tag == TTAG_slnt ) |
811 a->name = (char *)"Slant"; | 948 a->name = (char*)"Slant"; |
812 | 949 |
813 next_name += 5; | 950 next_name += 5; |
814 ++a; | 951 a++; |
815 } | 952 } |
816 | 953 |
817 *master = mmvar; | 954 *master = mmvar; |
818 } | 955 } |
819 | 956 |
820 Exit: | 957 Exit: |
821 return error; | 958 return error; |
822 } | 959 } |
823 | 960 |
824 | 961 |
825 /*************************************************************************/ | 962 /*************************************************************************/ |
826 /* */ | 963 /* */ |
827 /* <Function> */ | 964 /* <Function> */ |
828 /* TT_Set_MM_Blend */ | 965 /* TT_Set_MM_Blend */ |
829 /* */ | 966 /* */ |
830 /* <Description> */ | 967 /* <Description> */ |
831 /* Set the blend (normalized) coordinates for this instance of the */ | 968 /* Set the blend (normalized) coordinates for this instance of the */ |
832 /* font. Check that the `gvar' table is reasonable and does some */ | 969 /* font. Check that the `gvar' table is reasonable and does some */ |
833 /* initial preparation. */ | 970 /* initial preparation. */ |
834 /* */ | 971 /* */ |
835 /* <InOut> */ | 972 /* <InOut> */ |
836 /* face :: The font. */ | 973 /* face :: The font. */ |
837 /* Initialize the blend structure with `gvar' data. */ | 974 /* Initialize the blend structure with `gvar' data. */ |
838 /* */ | 975 /* */ |
839 /* <Input> */ | 976 /* <Input> */ |
840 /* num_coords :: Must be the axis count of the font. */ | 977 /* num_coords :: The number of available coordinates. If it is */ |
| 978 /* larger than the number of axes, ignore the excess */ |
| 979 /* values. If it is smaller than the number of axes, */ |
| 980 /* use the default value (0) for the remaining axes. */ |
841 /* */ | 981 /* */ |
842 /* coords :: An array of num_coords, each between [-1,1]. */ | 982 /* coords :: An array of `num_coords', each between [-1,1]. */ |
843 /* */ | 983 /* */ |
844 /* <Return> */ | 984 /* <Return> */ |
845 /* FreeType error code. 0 means success. */ | 985 /* FreeType error code. 0 means success. */ |
846 /* */ | 986 /* */ |
847 FT_LOCAL_DEF( FT_Error ) | 987 FT_LOCAL_DEF( FT_Error ) |
848 TT_Set_MM_Blend( TT_Face face, | 988 TT_Set_MM_Blend( TT_Face face, |
849 FT_UInt num_coords, | 989 FT_UInt num_coords, |
850 FT_Fixed* coords ) | 990 FT_Fixed* coords ) |
851 { | 991 { |
852 FT_Error error = FT_Err_Ok; | 992 FT_Error error = FT_Err_Ok; |
853 GX_Blend blend; | 993 GX_Blend blend; |
854 FT_MM_Var* mmvar; | 994 FT_MM_Var* mmvar; |
855 FT_UInt i; | 995 FT_UInt i; |
856 FT_Memory memory = face->root.memory; | 996 FT_Memory memory = face->root.memory; |
857 | 997 |
858 enum | 998 enum |
859 { | 999 { |
860 mcvt_retain, | 1000 mcvt_retain, |
861 mcvt_modify, | 1001 mcvt_modify, |
862 mcvt_load | 1002 mcvt_load |
863 | 1003 |
864 } manageCvt; | 1004 } manageCvt; |
865 | 1005 |
866 | 1006 |
867 face->doblend = FALSE; | 1007 face->doblend = FALSE; |
868 | 1008 |
869 if ( face->blend == NULL ) | 1009 if ( face->blend == NULL ) |
870 { | 1010 { |
871 if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) | 1011 if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) |
872 goto Exit; | 1012 goto Exit; |
873 } | 1013 } |
874 | 1014 |
875 blend = face->blend; | 1015 blend = face->blend; |
876 mmvar = blend->mmvar; | 1016 mmvar = blend->mmvar; |
877 | 1017 |
878 if ( num_coords != mmvar->num_axis ) | 1018 if ( num_coords > mmvar->num_axis ) |
879 { | 1019 { |
880 error = FT_THROW( Invalid_Argument ); | 1020 FT_TRACE2(( "TT_Set_MM_Blend: only using first %d of %d coordinates\n", |
881 goto Exit; | 1021 mmvar->num_axis, num_coords )); |
| 1022 num_coords = mmvar->num_axis; |
882 } | 1023 } |
883 | 1024 |
884 for ( i = 0; i < num_coords; ++i ) | 1025 FT_TRACE5(( "normalized design coordinates:\n" )); |
| 1026 |
| 1027 for ( i = 0; i < num_coords; i++ ) |
| 1028 { |
| 1029 FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); |
885 if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) | 1030 if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) |
886 { | 1031 { |
| 1032 FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.4f\n" |
| 1033 " is out of range [-1;1]\n", |
| 1034 coords[i] / 65536.0 )); |
887 error = FT_THROW( Invalid_Argument ); | 1035 error = FT_THROW( Invalid_Argument ); |
888 goto Exit; | 1036 goto Exit; |
889 } | 1037 } |
| 1038 } |
| 1039 |
| 1040 FT_TRACE5(( "\n" )); |
890 | 1041 |
891 if ( blend->glyphoffsets == NULL ) | 1042 if ( blend->glyphoffsets == NULL ) |
892 if ( (error = ft_var_load_gvar( face )) != 0 ) | 1043 if ( ( error = ft_var_load_gvar( face ) ) != 0 ) |
893 goto Exit; | 1044 goto Exit; |
894 | 1045 |
895 if ( blend->normalizedcoords == NULL ) | 1046 if ( blend->normalizedcoords == NULL ) |
896 { | 1047 { |
897 if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) | 1048 if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) |
898 goto Exit; | 1049 goto Exit; |
899 | 1050 |
900 manageCvt = mcvt_modify; | 1051 manageCvt = mcvt_modify; |
901 | 1052 |
902 /* If we have not set the blend coordinates before this, then the */ | 1053 /* If we have not set the blend coordinates before this, then the */ |
903 /* cvt table will still be what we read from the `cvt ' table and */ | 1054 /* cvt table will still be what we read from the `cvt ' table and */ |
904 /* we don't need to reload it. We may need to change it though... */ | 1055 /* we don't need to reload it. We may need to change it though... */ |
905 } | 1056 } |
906 else | 1057 else |
907 { | 1058 { |
908 manageCvt = mcvt_retain; | 1059 manageCvt = mcvt_retain; |
909 for ( i = 0; i < num_coords; ++i ) | 1060 |
| 1061 for ( i = 0; i < num_coords; i++ ) |
910 { | 1062 { |
911 if ( blend->normalizedcoords[i] != coords[i] ) | 1063 if ( blend->normalizedcoords[i] != coords[i] ) |
912 { | 1064 { |
913 manageCvt = mcvt_load; | 1065 manageCvt = mcvt_load; |
914 break; | 1066 break; |
915 } | 1067 } |
916 } | 1068 } |
917 | 1069 |
| 1070 for ( ; i < mmvar->num_axis; i++ ) |
| 1071 { |
| 1072 if ( blend->normalizedcoords[i] != 0 ) |
| 1073 { |
| 1074 manageCvt = mcvt_load; |
| 1075 break; |
| 1076 } |
| 1077 } |
| 1078 |
918 /* If we don't change the blend coords then we don't need to do */ | 1079 /* If we don't change the blend coords then we don't need to do */ |
919 /* anything to the cvt table. It will be correct. Otherwise we */ | 1080 /* anything to the cvt table. It will be correct. Otherwise we */ |
920 /* no longer have the original cvt (it was modified when we set */ | 1081 /* no longer have the original cvt (it was modified when we set */ |
921 /* the blend last time), so we must reload and then modify it. */ | 1082 /* the blend last time), so we must reload and then modify it. */ |
922 } | 1083 } |
923 | 1084 |
924 blend->num_axis = num_coords; | 1085 blend->num_axis = mmvar->num_axis; |
925 FT_MEM_COPY( blend->normalizedcoords, | 1086 FT_MEM_COPY( blend->normalizedcoords, |
926 coords, | 1087 coords, |
927 num_coords * sizeof ( FT_Fixed ) ); | 1088 num_coords * sizeof ( FT_Fixed ) ); |
928 | 1089 |
929 face->doblend = TRUE; | 1090 face->doblend = TRUE; |
930 | 1091 |
931 if ( face->cvt != NULL ) | 1092 if ( face->cvt != NULL ) |
932 { | 1093 { |
933 switch ( manageCvt ) | 1094 switch ( manageCvt ) |
934 { | 1095 { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
966 /* <Description> */ | 1127 /* <Description> */ |
967 /* Set the coordinates for the instance, measured in the user */ | 1128 /* Set the coordinates for the instance, measured in the user */ |
968 /* coordinate system. Parse the `avar' table (if present) to convert */ | 1129 /* coordinate system. Parse the `avar' table (if present) to convert */ |
969 /* from user to normalized coordinates. */ | 1130 /* from user to normalized coordinates. */ |
970 /* */ | 1131 /* */ |
971 /* <InOut> */ | 1132 /* <InOut> */ |
972 /* face :: The font face. */ | 1133 /* face :: The font face. */ |
973 /* Initialize the blend struct with `gvar' data. */ | 1134 /* Initialize the blend struct with `gvar' data. */ |
974 /* */ | 1135 /* */ |
975 /* <Input> */ | 1136 /* <Input> */ |
976 /* num_coords :: This must be the axis count of the font. */ | 1137 /* num_coords :: The number of available coordinates. If it is */ |
| 1138 /* larger than the number of axes, ignore the excess */ |
| 1139 /* values. If it is smaller than the number of axes, */ |
| 1140 /* use the default values for the remaining axes. */ |
977 /* */ | 1141 /* */ |
978 /* coords :: A coordinate array with `num_coords' elements. */ | 1142 /* coords :: A coordinate array with `num_coords' elements. */ |
979 /* */ | 1143 /* */ |
980 /* <Return> */ | 1144 /* <Return> */ |
981 /* FreeType error code. 0 means success. */ | 1145 /* FreeType error code. 0 means success. */ |
982 /* */ | 1146 /* */ |
983 FT_LOCAL_DEF( FT_Error ) | 1147 FT_LOCAL_DEF( FT_Error ) |
984 TT_Set_Var_Design( TT_Face face, | 1148 TT_Set_Var_Design( TT_Face face, |
985 FT_UInt num_coords, | 1149 FT_UInt num_coords, |
986 FT_Fixed* coords ) | 1150 FT_Fixed* coords ) |
987 { | 1151 { |
988 FT_Error error = FT_Err_Ok; | 1152 FT_Error error = FT_Err_Ok; |
989 FT_Fixed* normalized = NULL; | 1153 FT_Fixed* normalized = NULL; |
990 GX_Blend blend; | 1154 GX_Blend blend; |
991 FT_MM_Var* mmvar; | 1155 FT_MM_Var* mmvar; |
992 FT_UInt i, j; | 1156 FT_UInt i, j; |
993 FT_Var_Axis* a; | 1157 FT_Var_Axis* a; |
994 GX_AVarSegment av; | 1158 GX_AVarSegment av; |
995 FT_Memory memory = face->root.memory; | 1159 FT_Memory memory = face->root.memory; |
996 | 1160 |
997 | 1161 |
998 if ( face->blend == NULL ) | 1162 if ( face->blend == NULL ) |
999 { | 1163 { |
1000 if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) | 1164 if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) |
1001 goto Exit; | 1165 goto Exit; |
1002 } | 1166 } |
1003 | 1167 |
1004 blend = face->blend; | 1168 blend = face->blend; |
1005 mmvar = blend->mmvar; | 1169 mmvar = blend->mmvar; |
1006 | 1170 |
1007 if ( num_coords != mmvar->num_axis ) | 1171 if ( num_coords > mmvar->num_axis ) |
1008 { | 1172 { |
1009 error = FT_THROW( Invalid_Argument ); | 1173 FT_TRACE2(( "TT_Set_Var_Design:" |
1010 goto Exit; | 1174 " only using first %d of %d coordinates\n", |
| 1175 mmvar->num_axis, num_coords )); |
| 1176 num_coords = mmvar->num_axis; |
1011 } | 1177 } |
1012 | 1178 |
1013 /* Axis normalization is a two stage process. First we normalize */ | 1179 /* Axis normalization is a two stage process. First we normalize */ |
1014 /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ | 1180 /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ |
1015 /* Then, if there's an `avar' table, we renormalize this range. */ | 1181 /* Then, if there's an `avar' table, we renormalize this range. */ |
1016 | 1182 |
1017 if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) | 1183 if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) |
1018 goto Exit; | 1184 goto Exit; |
1019 | 1185 |
| 1186 FT_TRACE5(( "design coordinates:\n" )); |
| 1187 |
1020 a = mmvar->axis; | 1188 a = mmvar->axis; |
1021 for ( i = 0; i < mmvar->num_axis; ++i, ++a ) | 1189 for ( i = 0; i < num_coords; i++, a++ ) |
1022 { | 1190 { |
| 1191 FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); |
1023 if ( coords[i] > a->maximum || coords[i] < a->minimum ) | 1192 if ( coords[i] > a->maximum || coords[i] < a->minimum ) |
1024 { | 1193 { |
| 1194 FT_TRACE1(( "TT_Set_Var_Design: normalized design coordinate %.4f\n" |
| 1195 " is out of range [%.4f;%.4f]\n", |
| 1196 coords[i] / 65536.0, |
| 1197 a->minimum / 65536.0, |
| 1198 a->maximum / 65536.0 )); |
1025 error = FT_THROW( Invalid_Argument ); | 1199 error = FT_THROW( Invalid_Argument ); |
1026 goto Exit; | 1200 goto Exit; |
1027 } | 1201 } |
1028 | 1202 |
1029 if ( coords[i] < a->def ) | 1203 if ( coords[i] < a->def ) |
1030 normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def ); | 1204 normalized[i] = -FT_DivFix( coords[i] - a->def, |
| 1205 a->minimum - a->def ); |
1031 else if ( a->maximum == a->def ) | 1206 else if ( a->maximum == a->def ) |
1032 normalized[i] = 0; | 1207 normalized[i] = 0; |
1033 else | 1208 else |
1034 normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def ); | 1209 normalized[i] = FT_DivFix( coords[i] - a->def, |
| 1210 a->maximum - a->def ); |
1035 } | 1211 } |
1036 | 1212 |
| 1213 FT_TRACE5(( "\n" )); |
| 1214 |
| 1215 for ( ; i < mmvar->num_axis; i++ ) |
| 1216 normalized[i] = 0; |
| 1217 |
1037 if ( !blend->avar_checked ) | 1218 if ( !blend->avar_checked ) |
1038 ft_var_load_avar( face ); | 1219 ft_var_load_avar( face ); |
1039 | 1220 |
1040 if ( blend->avar_segment != NULL ) | 1221 if ( blend->avar_segment != NULL ) |
1041 { | 1222 { |
| 1223 FT_TRACE5(( "normalized design coordinates" |
| 1224 " before applying `avar' data:\n" )); |
| 1225 |
1042 av = blend->avar_segment; | 1226 av = blend->avar_segment; |
1043 for ( i = 0; i < mmvar->num_axis; ++i, ++av ) | 1227 for ( i = 0; i < mmvar->num_axis; i++, av++ ) |
1044 { | 1228 { |
1045 for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) | 1229 for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) |
| 1230 { |
| 1231 FT_TRACE5(( " %.4f\n", normalized[i] / 65536.0 )); |
1046 if ( normalized[i] < av->correspondence[j].fromCoord ) | 1232 if ( normalized[i] < av->correspondence[j].fromCoord ) |
1047 { | 1233 { |
1048 normalized[i] = | 1234 normalized[i] = |
1049 FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, | 1235 FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, |
1050 av->correspondence[j].toCoord - | 1236 av->correspondence[j].toCoord - |
1051 av->correspondence[j - 1].toCoord, | 1237 av->correspondence[j - 1].toCoord, |
1052 av->correspondence[j].fromCoord - | 1238 av->correspondence[j].fromCoord - |
1053 av->correspondence[j - 1].fromCoord ) + | 1239 av->correspondence[j - 1].fromCoord ) + |
1054 av->correspondence[j - 1].toCoord; | 1240 av->correspondence[j - 1].toCoord; |
1055 break; | 1241 break; |
1056 } | 1242 } |
| 1243 } |
1057 } | 1244 } |
1058 } | 1245 } |
1059 | 1246 |
1060 error = TT_Set_MM_Blend( face, num_coords, normalized ); | 1247 error = TT_Set_MM_Blend( face, mmvar->num_axis, normalized ); |
1061 | 1248 |
1062 Exit: | 1249 Exit: |
1063 FT_FREE( normalized ); | 1250 FT_FREE( normalized ); |
1064 return error; | 1251 return error; |
1065 } | 1252 } |
1066 | 1253 |
1067 | 1254 |
1068 /*************************************************************************/ | 1255 /*************************************************************************/ |
1069 /*************************************************************************/ | 1256 /*************************************************************************/ |
1070 /***** *****/ | 1257 /***** *****/ |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1113 GX_Blend blend = face->blend; | 1300 GX_Blend blend = face->blend; |
1114 FT_UInt point_count; | 1301 FT_UInt point_count; |
1115 FT_UShort* localpoints; | 1302 FT_UShort* localpoints; |
1116 FT_Short* deltas; | 1303 FT_Short* deltas; |
1117 | 1304 |
1118 | 1305 |
1119 FT_TRACE2(( "CVAR " )); | 1306 FT_TRACE2(( "CVAR " )); |
1120 | 1307 |
1121 if ( blend == NULL ) | 1308 if ( blend == NULL ) |
1122 { | 1309 { |
1123 FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); | 1310 FT_TRACE2(( "\n" |
1124 | 1311 "tt_face_vary_cvt: no blend specified\n" )); |
1125 error = FT_Err_Ok; | 1312 error = FT_Err_Ok; |
1126 goto Exit; | 1313 goto Exit; |
1127 } | 1314 } |
1128 | 1315 |
1129 if ( face->cvt == NULL ) | 1316 if ( face->cvt == NULL ) |
1130 { | 1317 { |
1131 FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); | 1318 FT_TRACE2(( "\n" |
1132 | 1319 "tt_face_vary_cvt: no `cvt ' table\n" )); |
1133 error = FT_Err_Ok; | 1320 error = FT_Err_Ok; |
1134 goto Exit; | 1321 goto Exit; |
1135 } | 1322 } |
1136 | 1323 |
1137 error = face->goto_table( face, TTAG_cvar, stream, &table_len ); | 1324 error = face->goto_table( face, TTAG_cvar, stream, &table_len ); |
1138 if ( error ) | 1325 if ( error ) |
1139 { | 1326 { |
1140 FT_TRACE2(( "is missing\n" )); | 1327 FT_TRACE2(( "is missing\n" )); |
1141 | 1328 |
1142 error = FT_Err_Ok; | 1329 error = FT_Err_Ok; |
1143 goto Exit; | 1330 goto Exit; |
1144 } | 1331 } |
1145 | 1332 |
1146 if ( FT_FRAME_ENTER( table_len ) ) | 1333 if ( FT_FRAME_ENTER( table_len ) ) |
1147 { | 1334 { |
1148 error = FT_Err_Ok; | 1335 error = FT_Err_Ok; |
1149 goto Exit; | 1336 goto Exit; |
1150 } | 1337 } |
1151 | 1338 |
1152 table_start = FT_Stream_FTell( stream ); | 1339 table_start = FT_Stream_FTell( stream ); |
1153 if ( FT_GET_LONG() != 0x00010000L ) | 1340 if ( FT_GET_LONG() != 0x00010000L ) |
1154 { | 1341 { |
1155 FT_TRACE2(( "bad table version\n" )); | 1342 FT_TRACE2(( "bad table version\n" )); |
1156 | 1343 |
1157 error = FT_Err_Ok; | 1344 error = FT_Err_Ok; |
1158 goto FExit; | 1345 goto FExit; |
1159 } | 1346 } |
1160 | 1347 |
| 1348 FT_TRACE2(( "loaded\n" )); |
| 1349 |
1161 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || | 1350 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || |
1162 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || | 1351 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || |
1163 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) | 1352 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) |
1164 goto FExit; | 1353 goto FExit; |
1165 | 1354 |
1166 tupleCount = FT_GET_USHORT(); | 1355 tupleCount = FT_GET_USHORT(); |
1167 offsetToData = table_start + FT_GET_USHORT(); | 1356 offsetToData = table_start + FT_GET_USHORT(); |
1168 | 1357 |
1169 /* The documentation implies there are flags packed into the */ | 1358 /* The documentation implies there are flags packed into the */ |
1170 /* tuplecount, but John Jenkins says that shared points don't apply */ | 1359 /* tuplecount, but John Jenkins says that shared points don't apply */ |
1171 /* to `cvar', and no other flags are defined. */ | 1360 /* to `cvar', and no other flags are defined. */ |
1172 | 1361 |
1173 for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) | 1362 FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount )); |
| 1363 |
| 1364 for ( i = 0; i < ( tupleCount & 0xFFF ); i++ ) |
1174 { | 1365 { |
1175 FT_UInt tupleDataSize; | 1366 FT_UInt tupleDataSize; |
1176 FT_UInt tupleIndex; | 1367 FT_UInt tupleIndex; |
1177 FT_Fixed apply; | 1368 FT_Fixed apply; |
1178 | 1369 |
1179 | 1370 |
| 1371 FT_TRACE6(( " tuple %d:\n", i )); |
| 1372 |
1180 tupleDataSize = FT_GET_USHORT(); | 1373 tupleDataSize = FT_GET_USHORT(); |
1181 tupleIndex = FT_GET_USHORT(); | 1374 tupleIndex = FT_GET_USHORT(); |
1182 | 1375 |
1183 /* There is no provision here for a global tuple coordinate section, */ | 1376 /* There is no provision here for a global tuple coordinate section, */ |
1184 /* so John says. There are no tuple indices, just embedded tuples. */ | 1377 /* so John says. There are no tuple indices, just embedded tuples. */ |
1185 | 1378 |
1186 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) | 1379 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) |
1187 { | 1380 { |
1188 for ( j = 0; j < blend->num_axis; ++j ) | 1381 for ( j = 0; j < blend->num_axis; j++ ) |
1189 tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ | 1382 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ |
1190 /* short frac to fixed */ | 1383 /* short frac to fixed */ |
1191 } | 1384 } |
1192 else | 1385 else |
1193 { | 1386 { |
1194 /* skip this tuple; it makes no sense */ | 1387 /* skip this tuple; it makes no sense */ |
1195 | 1388 |
1196 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) | 1389 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
1197 for ( j = 0; j < 2 * blend->num_axis; ++j ) | 1390 for ( j = 0; j < 2 * blend->num_axis; j++ ) |
1198 (void)FT_GET_SHORT(); | 1391 (void)FT_GET_SHORT(); |
1199 | 1392 |
1200 offsetToData += tupleDataSize; | 1393 offsetToData += tupleDataSize; |
1201 continue; | 1394 continue; |
1202 } | 1395 } |
1203 | 1396 |
1204 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) | 1397 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
1205 { | 1398 { |
1206 for ( j = 0; j < blend->num_axis; ++j ) | 1399 for ( j = 0; j < blend->num_axis; j++ ) |
1207 im_start_coords[j] = FT_GET_SHORT() << 2; | 1400 im_start_coords[j] = FT_GET_SHORT() * 4; |
1208 for ( j = 0; j < blend->num_axis; ++j ) | 1401 for ( j = 0; j < blend->num_axis; j++ ) |
1209 im_end_coords[j] = FT_GET_SHORT() << 2; | 1402 im_end_coords[j] = FT_GET_SHORT() * 4; |
1210 } | 1403 } |
1211 | 1404 |
1212 apply = ft_var_apply_tuple( blend, | 1405 apply = ft_var_apply_tuple( blend, |
1213 (FT_UShort)tupleIndex, | 1406 (FT_UShort)tupleIndex, |
1214 tuple_coords, | 1407 tuple_coords, |
1215 im_start_coords, | 1408 im_start_coords, |
1216 im_end_coords ); | 1409 im_end_coords ); |
1217 if ( /* tuple isn't active for our blend */ | 1410 if ( /* tuple isn't active for our blend */ |
1218 apply == 0 || | 1411 apply == 0 || |
1219 /* global points not allowed, */ | 1412 /* global points not allowed, */ |
1220 /* if they aren't local, makes no sense */ | 1413 /* if they aren't local, makes no sense */ |
1221 !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) | 1414 !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) |
1222 { | 1415 { |
1223 offsetToData += tupleDataSize; | 1416 offsetToData += tupleDataSize; |
1224 continue; | 1417 continue; |
1225 } | 1418 } |
1226 | 1419 |
1227 here = FT_Stream_FTell( stream ); | 1420 here = FT_Stream_FTell( stream ); |
1228 | 1421 |
1229 FT_Stream_SeekSet( stream, offsetToData ); | 1422 FT_Stream_SeekSet( stream, offsetToData ); |
1230 | 1423 |
1231 localpoints = ft_var_readpackedpoints( stream, &point_count ); | 1424 localpoints = ft_var_readpackedpoints( stream, &point_count ); |
1232 deltas = ft_var_readpackeddeltas( stream, | 1425 deltas = ft_var_readpackeddeltas( stream, |
1233 point_count == 0 ? face->cvt_size | 1426 point_count == 0 ? face->cvt_size |
1234 : point_count ); | 1427 : point_count ); |
1235 if ( localpoints == NULL || deltas == NULL ) | 1428 if ( localpoints == NULL || deltas == NULL ) |
1236 /* failure, ignore it */; | 1429 ; /* failure, ignore it */ |
1237 | 1430 |
1238 else if ( localpoints == ALL_POINTS ) | 1431 else if ( localpoints == ALL_POINTS ) |
1239 { | 1432 { |
| 1433 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1434 int count = 0; |
| 1435 #endif |
| 1436 |
| 1437 |
| 1438 FT_TRACE7(( " CVT deltas:\n" )); |
| 1439 |
1240 /* this means that there are deltas for every entry in cvt */ | 1440 /* this means that there are deltas for every entry in cvt */ |
1241 for ( j = 0; j < face->cvt_size; ++j ) | 1441 for ( j = 0; j < face->cvt_size; j++ ) |
1242 face->cvt[j] = (FT_Short)( face->cvt[j] + | 1442 { |
| 1443 FT_Long orig_cvt = face->cvt[j]; |
| 1444 |
| 1445 |
| 1446 face->cvt[j] = (FT_Short)( orig_cvt + |
1243 FT_MulFix( deltas[j], apply ) ); | 1447 FT_MulFix( deltas[j], apply ) ); |
| 1448 |
| 1449 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1450 if ( orig_cvt != face->cvt[j] ) |
| 1451 { |
| 1452 FT_TRACE7(( " %d: %d -> %d\n", |
| 1453 j, orig_cvt, face->cvt[j] )); |
| 1454 count++; |
| 1455 } |
| 1456 #endif |
| 1457 } |
| 1458 |
| 1459 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1460 if ( !count ) |
| 1461 FT_TRACE7(( " none\n" )); |
| 1462 #endif |
1244 } | 1463 } |
1245 | 1464 |
1246 else | 1465 else |
1247 { | 1466 { |
1248 for ( j = 0; j < point_count; ++j ) | 1467 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1468 int count = 0; |
| 1469 #endif |
| 1470 |
| 1471 |
| 1472 FT_TRACE7(( " CVT deltas:\n" )); |
| 1473 |
| 1474 for ( j = 0; j < point_count; j++ ) |
1249 { | 1475 { |
1250 int pindex = localpoints[j]; | 1476 int pindex = localpoints[j]; |
| 1477 FT_Long orig_cvt = face->cvt[pindex]; |
1251 | 1478 |
1252 face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + | 1479 |
| 1480 face->cvt[pindex] = (FT_Short)( orig_cvt + |
1253 FT_MulFix( deltas[j], apply ) ); | 1481 FT_MulFix( deltas[j], apply ) ); |
| 1482 |
| 1483 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1484 if ( orig_cvt != face->cvt[pindex] ) |
| 1485 { |
| 1486 FT_TRACE7(( " %d: %d -> %d\n", |
| 1487 pindex, orig_cvt, face->cvt[pindex] )); |
| 1488 count++; |
| 1489 } |
| 1490 #endif |
1254 } | 1491 } |
| 1492 |
| 1493 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1494 if ( !count ) |
| 1495 FT_TRACE7(( " none\n" )); |
| 1496 #endif |
1255 } | 1497 } |
1256 | 1498 |
1257 if ( localpoints != ALL_POINTS ) | 1499 if ( localpoints != ALL_POINTS ) |
1258 FT_FREE( localpoints ); | 1500 FT_FREE( localpoints ); |
1259 FT_FREE( deltas ); | 1501 FT_FREE( deltas ); |
1260 | 1502 |
1261 offsetToData += tupleDataSize; | 1503 offsetToData += tupleDataSize; |
1262 | 1504 |
1263 FT_Stream_SeekSet( stream, here ); | 1505 FT_Stream_SeekSet( stream, here ); |
1264 } | 1506 } |
1265 | 1507 |
| 1508 FT_TRACE5(( "\n" )); |
| 1509 |
1266 FExit: | 1510 FExit: |
1267 FT_FRAME_EXIT(); | 1511 FT_FRAME_EXIT(); |
1268 | 1512 |
1269 Exit: | 1513 Exit: |
1270 FT_FREE( tuple_coords ); | 1514 FT_FREE( tuple_coords ); |
1271 FT_FREE( im_start_coords ); | 1515 FT_FREE( im_start_coords ); |
1272 FT_FREE( im_end_coords ); | 1516 FT_FREE( im_end_coords ); |
1273 | 1517 |
1274 return error; | 1518 return error; |
1275 } | 1519 } |
1276 | 1520 |
1277 | 1521 |
| 1522 /* Shift the original coordinates of all points between indices `p1' */ |
| 1523 /* and `p2', using the same difference as given by index `ref'. */ |
| 1524 |
| 1525 /* modeled after `af_iup_shift' */ |
| 1526 |
| 1527 static void |
| 1528 tt_delta_shift( int p1, |
| 1529 int p2, |
| 1530 int ref, |
| 1531 FT_Vector* in_points, |
| 1532 FT_Vector* out_points ) |
| 1533 { |
| 1534 int p; |
| 1535 FT_Vector delta; |
| 1536 |
| 1537 |
| 1538 delta.x = out_points[ref].x - in_points[ref].x; |
| 1539 delta.y = out_points[ref].y - in_points[ref].y; |
| 1540 |
| 1541 if ( delta.x == 0 && delta.y == 0 ) |
| 1542 return; |
| 1543 |
| 1544 for ( p = p1; p < ref; p++ ) |
| 1545 { |
| 1546 out_points[p].x += delta.x; |
| 1547 out_points[p].y += delta.y; |
| 1548 } |
| 1549 |
| 1550 for ( p = ref + 1; p <= p2; p++ ) |
| 1551 { |
| 1552 out_points[p].x += delta.x; |
| 1553 out_points[p].y += delta.y; |
| 1554 } |
| 1555 } |
| 1556 |
| 1557 |
| 1558 /* Interpolate the original coordinates of all points with indices */ |
| 1559 /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ |
| 1560 /* point indices. */ |
| 1561 |
| 1562 /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ |
| 1563 /* `Ins_IUP' */ |
| 1564 |
| 1565 static void |
| 1566 tt_delta_interpolate( int p1, |
| 1567 int p2, |
| 1568 int ref1, |
| 1569 int ref2, |
| 1570 FT_Vector* in_points, |
| 1571 FT_Vector* out_points ) |
| 1572 { |
| 1573 int p, i; |
| 1574 |
| 1575 FT_Pos out, in1, in2, out1, out2, d1, d2; |
| 1576 |
| 1577 |
| 1578 if ( p1 > p2 ) |
| 1579 return; |
| 1580 |
| 1581 /* handle both horizontal and vertical coordinates */ |
| 1582 for ( i = 0; i <= 1; i++ ) |
| 1583 { |
| 1584 /* shift array pointers so that we can access `foo.y' as `foo.x' */ |
| 1585 in_points = (FT_Vector*)( (FT_Pos*)in_points + i ); |
| 1586 out_points = (FT_Vector*)( (FT_Pos*)out_points + i ); |
| 1587 |
| 1588 if ( in_points[ref1].x > in_points[ref2].x ) |
| 1589 { |
| 1590 p = ref1; |
| 1591 ref1 = ref2; |
| 1592 ref2 = p; |
| 1593 } |
| 1594 |
| 1595 in1 = in_points[ref1].x; |
| 1596 in2 = in_points[ref2].x; |
| 1597 out1 = out_points[ref1].x; |
| 1598 out2 = out_points[ref2].x; |
| 1599 d1 = out1 - in1; |
| 1600 d2 = out2 - in2; |
| 1601 |
| 1602 if ( out1 == out2 || in1 == in2 ) |
| 1603 { |
| 1604 for ( p = p1; p <= p2; p++ ) |
| 1605 { |
| 1606 out = in_points[p].x; |
| 1607 |
| 1608 if ( out <= in1 ) |
| 1609 out += d1; |
| 1610 else if ( out >= in2 ) |
| 1611 out += d2; |
| 1612 else |
| 1613 out = out1; |
| 1614 |
| 1615 out_points[p].x = out; |
| 1616 } |
| 1617 } |
| 1618 else |
| 1619 { |
| 1620 FT_Fixed scale = FT_DivFix( out2 - out1, in2 - in1 ); |
| 1621 |
| 1622 |
| 1623 for ( p = p1; p <= p2; p++ ) |
| 1624 { |
| 1625 out = in_points[p].x; |
| 1626 |
| 1627 if ( out <= in1 ) |
| 1628 out += d1; |
| 1629 else if ( out >= in2 ) |
| 1630 out += d2; |
| 1631 else |
| 1632 out = out1 + FT_MulFix( out - in1, scale ); |
| 1633 |
| 1634 out_points[p].x = out; |
| 1635 } |
| 1636 } |
| 1637 } |
| 1638 } |
| 1639 |
| 1640 |
| 1641 /* Interpolate points without delta values, similar to */ |
| 1642 /* the `IUP' hinting instruction. */ |
| 1643 |
| 1644 /* modeled after `Ins_IUP */ |
| 1645 |
| 1646 static void |
| 1647 tt_handle_deltas( FT_Outline* outline, |
| 1648 FT_Vector* in_points, |
| 1649 FT_Bool* has_delta ) |
| 1650 { |
| 1651 FT_Vector* out_points; |
| 1652 |
| 1653 FT_Int first_point; |
| 1654 FT_Int end_point; |
| 1655 |
| 1656 FT_Int first_delta; |
| 1657 FT_Int cur_delta; |
| 1658 |
| 1659 FT_Int point; |
| 1660 FT_Short contour; |
| 1661 |
| 1662 |
| 1663 /* ignore empty outlines */ |
| 1664 if ( !outline->n_contours ) |
| 1665 return; |
| 1666 |
| 1667 out_points = outline->points; |
| 1668 |
| 1669 contour = 0; |
| 1670 point = 0; |
| 1671 |
| 1672 do |
| 1673 { |
| 1674 end_point = outline->contours[contour]; |
| 1675 first_point = point; |
| 1676 |
| 1677 /* search first point that has a delta */ |
| 1678 while ( point <= end_point && !has_delta[point] ) |
| 1679 point++; |
| 1680 |
| 1681 if ( point <= end_point ) |
| 1682 { |
| 1683 first_delta = point; |
| 1684 cur_delta = point; |
| 1685 |
| 1686 point++; |
| 1687 |
| 1688 while ( point <= end_point ) |
| 1689 { |
| 1690 /* search next point that has a delta */ |
| 1691 /* and interpolate intermediate points */ |
| 1692 if ( has_delta[point] ) |
| 1693 { |
| 1694 tt_delta_interpolate( cur_delta + 1, |
| 1695 point - 1, |
| 1696 cur_delta, |
| 1697 point, |
| 1698 in_points, |
| 1699 out_points ); |
| 1700 cur_delta = point; |
| 1701 } |
| 1702 |
| 1703 point++; |
| 1704 } |
| 1705 |
| 1706 /* shift contour if we only have a single delta */ |
| 1707 if ( cur_delta == first_delta ) |
| 1708 tt_delta_shift( first_point, |
| 1709 end_point, |
| 1710 cur_delta, |
| 1711 in_points, |
| 1712 out_points ); |
| 1713 else |
| 1714 { |
| 1715 /* otherwise handle remaining points */ |
| 1716 /* at the end and beginning of the contour */ |
| 1717 tt_delta_interpolate( cur_delta + 1, |
| 1718 end_point, |
| 1719 cur_delta, |
| 1720 first_delta, |
| 1721 in_points, |
| 1722 out_points ); |
| 1723 |
| 1724 if ( first_delta > 0 ) |
| 1725 tt_delta_interpolate( first_point, |
| 1726 first_delta - 1, |
| 1727 cur_delta, |
| 1728 first_delta, |
| 1729 in_points, |
| 1730 out_points ); |
| 1731 } |
| 1732 } |
| 1733 contour++; |
| 1734 |
| 1735 } while ( contour < outline->n_contours ); |
| 1736 } |
| 1737 |
| 1738 |
1278 /*************************************************************************/ | 1739 /*************************************************************************/ |
1279 /* */ | 1740 /* */ |
1280 /* <Function> */ | 1741 /* <Function> */ |
1281 /* TT_Vary_Get_Glyph_Deltas */ | 1742 /* TT_Vary_Apply_Glyph_Deltas */ |
1282 /* */ | 1743 /* */ |
1283 /* <Description> */ | 1744 /* <Description> */ |
1284 /* Load the appropriate deltas for the current glyph. */ | 1745 /* Apply the appropriate deltas to the current glyph. */ |
1285 /* */ | 1746 /* */ |
1286 /* <Input> */ | 1747 /* <Input> */ |
1287 /* face :: A handle to the target face object. */ | 1748 /* face :: A handle to the target face object. */ |
1288 /* */ | 1749 /* */ |
1289 /* glyph_index :: The index of the glyph being modified. */ | 1750 /* glyph_index :: The index of the glyph being modified. */ |
1290 /* */ | 1751 /* */ |
1291 /* n_points :: The number of the points in the glyph, including */ | 1752 /* n_points :: The number of the points in the glyph, including */ |
1292 /* phantom points. */ | 1753 /* phantom points. */ |
1293 /* */ | 1754 /* */ |
1294 /* <Output> */ | 1755 /* <InOut> */ |
1295 /* deltas :: The array of points to change. */ | 1756 /* outline :: The outline to change. */ |
1296 /* */ | 1757 /* */ |
1297 /* <Return> */ | 1758 /* <Return> */ |
1298 /* FreeType error code. 0 means success. */ | 1759 /* FreeType error code. 0 means success. */ |
1299 /* */ | 1760 /* */ |
1300 FT_LOCAL_DEF( FT_Error ) | 1761 FT_LOCAL_DEF( FT_Error ) |
1301 TT_Vary_Get_Glyph_Deltas( TT_Face face, | 1762 TT_Vary_Apply_Glyph_Deltas( TT_Face face, |
1302 FT_UInt glyph_index, | 1763 FT_UInt glyph_index, |
1303 FT_Vector* *deltas, | 1764 FT_Outline* outline, |
1304 FT_UInt n_points ) | 1765 FT_UInt n_points ) |
1305 { | 1766 { |
1306 FT_Stream stream = face->root.stream; | 1767 FT_Stream stream = face->root.stream; |
1307 FT_Memory memory = stream->memory; | 1768 FT_Memory memory = stream->memory; |
1308 GX_Blend blend = face->blend; | 1769 GX_Blend blend = face->blend; |
1309 FT_Vector* delta_xy = NULL; | 1770 |
| 1771 FT_Vector* points_org = NULL; |
| 1772 FT_Bool* has_delta = NULL; |
1310 | 1773 |
1311 FT_Error error; | 1774 FT_Error error; |
1312 FT_ULong glyph_start; | 1775 FT_ULong glyph_start; |
1313 FT_UInt tupleCount; | 1776 FT_UInt tupleCount; |
1314 FT_ULong offsetToData; | 1777 FT_ULong offsetToData; |
1315 FT_ULong here; | 1778 FT_ULong here; |
1316 FT_UInt i, j; | 1779 FT_UInt i, j; |
1317 FT_Fixed* tuple_coords = NULL; | 1780 FT_Fixed* tuple_coords = NULL; |
1318 FT_Fixed* im_start_coords = NULL; | 1781 FT_Fixed* im_start_coords = NULL; |
1319 FT_Fixed* im_end_coords = NULL; | 1782 FT_Fixed* im_end_coords = NULL; |
1320 FT_UInt point_count, spoint_count = 0; | 1783 FT_UInt point_count, spoint_count = 0; |
1321 FT_UShort* sharedpoints = NULL; | 1784 FT_UShort* sharedpoints = NULL; |
1322 FT_UShort* localpoints = NULL; | 1785 FT_UShort* localpoints = NULL; |
1323 FT_UShort* points; | 1786 FT_UShort* points; |
1324 FT_Short *deltas_x, *deltas_y; | 1787 FT_Short *deltas_x, *deltas_y; |
1325 | 1788 |
1326 | 1789 |
1327 if ( !face->doblend || blend == NULL ) | 1790 if ( !face->doblend || blend == NULL ) |
1328 return FT_THROW( Invalid_Argument ); | 1791 return FT_THROW( Invalid_Argument ); |
1329 | 1792 |
1330 /* to be freed by the caller */ | |
1331 if ( FT_NEW_ARRAY( delta_xy, n_points ) ) | |
1332 goto Exit; | |
1333 *deltas = delta_xy; | |
1334 | |
1335 if ( glyph_index >= blend->gv_glyphcnt || | 1793 if ( glyph_index >= blend->gv_glyphcnt || |
1336 blend->glyphoffsets[glyph_index] == | 1794 blend->glyphoffsets[glyph_index] == |
1337 blend->glyphoffsets[glyph_index + 1] ) | 1795 blend->glyphoffsets[glyph_index + 1] ) |
1338 return FT_Err_Ok; /* no variation data for this glyph */ | 1796 { |
| 1797 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" |
| 1798 " no variation data for this glyph\n" )); |
| 1799 return FT_Err_Ok; |
| 1800 } |
| 1801 |
| 1802 if ( FT_NEW_ARRAY( points_org, n_points ) || |
| 1803 FT_NEW_ARRAY( has_delta, n_points ) ) |
| 1804 goto Fail1; |
1339 | 1805 |
1340 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || | 1806 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || |
1341 FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - | 1807 FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - |
1342 blend->glyphoffsets[glyph_index] ) ) | 1808 blend->glyphoffsets[glyph_index] ) ) |
1343 goto Fail1; | 1809 goto Fail1; |
1344 | 1810 |
1345 glyph_start = FT_Stream_FTell( stream ); | 1811 glyph_start = FT_Stream_FTell( stream ); |
1346 | 1812 |
1347 /* each set of glyph variation data is formatted similarly to `cvar' */ | 1813 /* each set of glyph variation data is formatted similarly to `cvar' */ |
1348 /* (except we get shared points and global tuples) */ | 1814 /* (except we get shared points and global tuples) */ |
(...skipping 11 matching lines...) Expand all Loading... |
1360 here = FT_Stream_FTell( stream ); | 1826 here = FT_Stream_FTell( stream ); |
1361 | 1827 |
1362 FT_Stream_SeekSet( stream, offsetToData ); | 1828 FT_Stream_SeekSet( stream, offsetToData ); |
1363 | 1829 |
1364 sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); | 1830 sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); |
1365 offsetToData = FT_Stream_FTell( stream ); | 1831 offsetToData = FT_Stream_FTell( stream ); |
1366 | 1832 |
1367 FT_Stream_SeekSet( stream, here ); | 1833 FT_Stream_SeekSet( stream, here ); |
1368 } | 1834 } |
1369 | 1835 |
1370 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) | 1836 FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount )); |
| 1837 |
| 1838 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) |
1371 { | 1839 { |
1372 FT_UInt tupleDataSize; | 1840 FT_UInt tupleDataSize; |
1373 FT_UInt tupleIndex; | 1841 FT_UInt tupleIndex; |
1374 FT_Fixed apply; | 1842 FT_Fixed apply; |
1375 | 1843 |
1376 | 1844 |
| 1845 FT_TRACE6(( " tuple %d:\n", i )); |
| 1846 |
1377 tupleDataSize = FT_GET_USHORT(); | 1847 tupleDataSize = FT_GET_USHORT(); |
1378 tupleIndex = FT_GET_USHORT(); | 1848 tupleIndex = FT_GET_USHORT(); |
1379 | 1849 |
1380 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) | 1850 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) |
1381 { | 1851 { |
1382 for ( j = 0; j < blend->num_axis; ++j ) | 1852 for ( j = 0; j < blend->num_axis; j++ ) |
1383 tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ | 1853 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ |
1384 /* short frac to fixed */ | 1854 /* short frac to fixed */ |
1385 } | 1855 } |
1386 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) | 1856 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) |
1387 { | 1857 { |
1388 error = FT_THROW( Invalid_Table ); | 1858 error = FT_THROW( Invalid_Table ); |
1389 goto Fail3; | 1859 goto Fail2; |
1390 } | 1860 } |
1391 else | 1861 else |
1392 { | |
1393 FT_MEM_COPY( | 1862 FT_MEM_COPY( |
1394 tuple_coords, | 1863 tuple_coords, |
1395 &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], | 1864 &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], |
1396 blend->num_axis * sizeof ( FT_Fixed ) ); | 1865 blend->num_axis * sizeof ( FT_Fixed ) ); |
1397 } | |
1398 | 1866 |
1399 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) | 1867 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) |
1400 { | 1868 { |
1401 for ( j = 0; j < blend->num_axis; ++j ) | 1869 for ( j = 0; j < blend->num_axis; j++ ) |
1402 im_start_coords[j] = FT_GET_SHORT() << 2; | 1870 im_start_coords[j] = FT_GET_SHORT() * 4; |
1403 for ( j = 0; j < blend->num_axis; ++j ) | 1871 for ( j = 0; j < blend->num_axis; j++ ) |
1404 im_end_coords[j] = FT_GET_SHORT() << 2; | 1872 im_end_coords[j] = FT_GET_SHORT() * 4; |
1405 } | 1873 } |
1406 | 1874 |
1407 apply = ft_var_apply_tuple( blend, | 1875 apply = ft_var_apply_tuple( blend, |
1408 (FT_UShort)tupleIndex, | 1876 (FT_UShort)tupleIndex, |
1409 tuple_coords, | 1877 tuple_coords, |
1410 im_start_coords, | 1878 im_start_coords, |
1411 im_end_coords ); | 1879 im_end_coords ); |
1412 | 1880 |
1413 if ( apply == 0 ) /* tuple isn't active for our blend */ | 1881 if ( apply == 0 ) /* tuple isn't active for our blend */ |
1414 { | 1882 { |
(...skipping 21 matching lines...) Expand all Loading... |
1436 : point_count ); | 1904 : point_count ); |
1437 deltas_y = ft_var_readpackeddeltas( stream, | 1905 deltas_y = ft_var_readpackeddeltas( stream, |
1438 point_count == 0 ? n_points | 1906 point_count == 0 ? n_points |
1439 : point_count ); | 1907 : point_count ); |
1440 | 1908 |
1441 if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) | 1909 if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) |
1442 ; /* failure, ignore it */ | 1910 ; /* failure, ignore it */ |
1443 | 1911 |
1444 else if ( points == ALL_POINTS ) | 1912 else if ( points == ALL_POINTS ) |
1445 { | 1913 { |
| 1914 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1915 int count = 0; |
| 1916 #endif |
| 1917 |
| 1918 |
| 1919 FT_TRACE7(( " point deltas:\n" )); |
| 1920 |
1446 /* this means that there are deltas for every point in the glyph */ | 1921 /* this means that there are deltas for every point in the glyph */ |
1447 for ( j = 0; j < n_points; ++j ) | 1922 for ( j = 0; j < n_points; j++ ) |
1448 { | 1923 { |
1449 delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); | 1924 #ifdef FT_DEBUG_LEVEL_TRACE |
1450 delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); | 1925 FT_Vector point_org = outline->points[j]; |
| 1926 #endif |
| 1927 |
| 1928 |
| 1929 outline->points[j].x += FT_MulFix( deltas_x[j], apply ); |
| 1930 outline->points[j].y += FT_MulFix( deltas_y[j], apply ); |
| 1931 |
| 1932 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1933 if ( ( point_org.x != outline->points[j].x ) || |
| 1934 ( point_org.y != outline->points[j].y ) ) |
| 1935 { |
| 1936 FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", |
| 1937 j, |
| 1938 point_org.x, |
| 1939 point_org.y, |
| 1940 outline->points[j].x, |
| 1941 outline->points[j].y )); |
| 1942 count++; |
| 1943 } |
| 1944 #endif |
1451 } | 1945 } |
| 1946 |
| 1947 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1948 if ( !count ) |
| 1949 FT_TRACE7(( " none\n" )); |
| 1950 #endif |
1452 } | 1951 } |
1453 | 1952 |
1454 else | 1953 else |
1455 { | 1954 { |
1456 for ( j = 0; j < point_count; ++j ) | 1955 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1956 int count = 0; |
| 1957 #endif |
| 1958 |
| 1959 |
| 1960 /* we have to interpolate the missing deltas similar to the */ |
| 1961 /* IUP bytecode instruction */ |
| 1962 for ( j = 0; j < n_points; j++ ) |
1457 { | 1963 { |
1458 if ( localpoints[j] >= n_points ) | 1964 points_org[j] = outline->points[j]; |
| 1965 has_delta[j] = FALSE; |
| 1966 } |
| 1967 |
| 1968 for ( j = 0; j < point_count; j++ ) |
| 1969 { |
| 1970 FT_UShort idx = localpoints[j]; |
| 1971 |
| 1972 |
| 1973 if ( idx >= n_points ) |
1459 continue; | 1974 continue; |
1460 | 1975 |
1461 delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); | 1976 has_delta[idx] = TRUE; |
1462 delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); | 1977 |
| 1978 outline->points[idx].x += FT_MulFix( deltas_x[j], apply ); |
| 1979 outline->points[idx].y += FT_MulFix( deltas_y[j], apply ); |
1463 } | 1980 } |
| 1981 |
| 1982 /* no need to handle phantom points here, */ |
| 1983 /* since solitary points can't be interpolated */ |
| 1984 tt_handle_deltas( outline, |
| 1985 points_org, |
| 1986 has_delta ); |
| 1987 |
| 1988 #ifdef FT_DEBUG_LEVEL_TRACE |
| 1989 FT_TRACE7(( " point deltas:\n" )); |
| 1990 |
| 1991 for ( j = 0; j < n_points; j++) |
| 1992 { |
| 1993 if ( ( points_org[j].x != outline->points[j].x ) || |
| 1994 ( points_org[j].y != outline->points[j].y ) ) |
| 1995 { |
| 1996 FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", |
| 1997 j, |
| 1998 points_org[j].x, |
| 1999 points_org[j].y, |
| 2000 outline->points[j].x, |
| 2001 outline->points[j].y )); |
| 2002 count++; |
| 2003 } |
| 2004 } |
| 2005 |
| 2006 if ( !count ) |
| 2007 FT_TRACE7(( " none\n" )); |
| 2008 #endif |
1464 } | 2009 } |
1465 | 2010 |
1466 if ( localpoints != ALL_POINTS ) | 2011 if ( localpoints != ALL_POINTS ) |
1467 FT_FREE( localpoints ); | 2012 FT_FREE( localpoints ); |
1468 FT_FREE( deltas_x ); | 2013 FT_FREE( deltas_x ); |
1469 FT_FREE( deltas_y ); | 2014 FT_FREE( deltas_y ); |
1470 | 2015 |
1471 offsetToData += tupleDataSize; | 2016 offsetToData += tupleDataSize; |
1472 | 2017 |
1473 FT_Stream_SeekSet( stream, here ); | 2018 FT_Stream_SeekSet( stream, here ); |
1474 } | 2019 } |
1475 | 2020 |
1476 Fail3: | 2021 FT_TRACE5(( "\n" )); |
| 2022 |
| 2023 Fail2: |
1477 FT_FREE( tuple_coords ); | 2024 FT_FREE( tuple_coords ); |
1478 FT_FREE( im_start_coords ); | 2025 FT_FREE( im_start_coords ); |
1479 FT_FREE( im_end_coords ); | 2026 FT_FREE( im_end_coords ); |
1480 | 2027 |
1481 Fail2: | |
1482 FT_FRAME_EXIT(); | 2028 FT_FRAME_EXIT(); |
1483 | 2029 |
1484 Fail1: | 2030 Fail1: |
1485 if ( error ) | 2031 FT_FREE( points_org ); |
1486 { | 2032 FT_FREE( has_delta ); |
1487 FT_FREE( delta_xy ); | |
1488 *deltas = NULL; | |
1489 } | |
1490 | 2033 |
1491 Exit: | |
1492 return error; | 2034 return error; |
1493 } | 2035 } |
1494 | 2036 |
1495 | 2037 |
1496 /*************************************************************************/ | 2038 /*************************************************************************/ |
1497 /* */ | 2039 /* */ |
1498 /* <Function> */ | 2040 /* <Function> */ |
1499 /* tt_done_blend */ | 2041 /* tt_done_blend */ |
1500 /* */ | 2042 /* */ |
1501 /* <Description> */ | 2043 /* <Description> */ |
1502 /* Frees the blend internal data structure. */ | 2044 /* Free the blend internal data structure. */ |
1503 /* */ | 2045 /* */ |
1504 FT_LOCAL_DEF( void ) | 2046 FT_LOCAL_DEF( void ) |
1505 tt_done_blend( FT_Memory memory, | 2047 tt_done_blend( FT_Memory memory, |
1506 GX_Blend blend ) | 2048 GX_Blend blend ) |
1507 { | 2049 { |
1508 if ( blend != NULL ) | 2050 if ( blend != NULL ) |
1509 { | 2051 { |
1510 FT_UInt i; | 2052 FT_UInt i; |
1511 | 2053 |
1512 | 2054 |
1513 FT_FREE( blend->normalizedcoords ); | 2055 FT_FREE( blend->normalizedcoords ); |
1514 FT_FREE( blend->mmvar ); | 2056 FT_FREE( blend->mmvar ); |
1515 | 2057 |
1516 if ( blend->avar_segment != NULL ) | 2058 if ( blend->avar_segment != NULL ) |
1517 { | 2059 { |
1518 for ( i = 0; i < blend->num_axis; ++i ) | 2060 for ( i = 0; i < blend->num_axis; i++ ) |
1519 FT_FREE( blend->avar_segment[i].correspondence ); | 2061 FT_FREE( blend->avar_segment[i].correspondence ); |
1520 FT_FREE( blend->avar_segment ); | 2062 FT_FREE( blend->avar_segment ); |
1521 } | 2063 } |
1522 | 2064 |
1523 FT_FREE( blend->tuplecoords ); | 2065 FT_FREE( blend->tuplecoords ); |
1524 FT_FREE( blend->glyphoffsets ); | 2066 FT_FREE( blend->glyphoffsets ); |
1525 FT_FREE( blend ); | 2067 FT_FREE( blend ); |
1526 } | 2068 } |
1527 } | 2069 } |
1528 | 2070 |
1529 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ | 2071 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ |
1530 | 2072 |
1531 | 2073 |
1532 /* END */ | 2074 /* END */ |
OLD | NEW |