blob: eeb2ae4096e061f6cefcd34c3a09af19ec31f248 [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
3/* ttgload.c */
4/* */
5/* TrueType Glyph Loader (body). */
6/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007/* Copyright 1996-2000 by */
David Turnerd2b1f351999-12-16 23:11:37 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000010/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000012/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
David Turnerefce08d2000-05-11 18:23:52 +000019#include <freetype/internal/ftdebug.h>
20#include <freetype/internal/ftcalc.h>
21#include <freetype/internal/ftstream.h>
22#include <freetype/internal/sfnt.h>
23#include <freetype/tttags.h>
David Turnerf9ca2bb2000-06-30 23:12:55 +000024#include <freetype/ftoutln.h>
David Turnerd2b1f351999-12-16 23:11:37 +000025
David Turnerd2b1f351999-12-16 23:11:37 +000026
Werner Lemberg7fa51b52000-07-08 19:51:42 +000027#ifdef FT_FLAT_COMPILE
28
29#include "ttgload.h"
30
31#else
32
33#include <truetype/ttgload.h>
34
35#endif
Werner Lemberg78575dc2000-06-12 19:36:41 +000036
David Turnera90663f2000-07-08 00:41:13 +000037
Werner Lemberg78575dc2000-06-12 19:36:41 +000038 /*************************************************************************/
39 /* */
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
43 /* */
David Turnerd2b1f351999-12-16 23:11:37 +000044#undef FT_COMPONENT
45#define FT_COMPONENT trace_ttgload
46
47
48 /*************************************************************************/
49 /* */
50 /* Composite font flags. */
51 /* */
52#define ARGS_ARE_WORDS 0x001
53#define ARGS_ARE_XY_VALUES 0x002
54#define ROUND_XY_TO_GRID 0x004
55#define WE_HAVE_A_SCALE 0x008
56/* reserved 0x010 */
57#define MORE_COMPONENTS 0x020
58#define WE_HAVE_AN_XY_SCALE 0x040
59#define WE_HAVE_A_2X2 0x080
60#define WE_HAVE_INSTR 0x100
61#define USE_MY_METRICS 0x200
62
63
David Turnerf9b8dec2000-06-16 19:34:52 +000064
David Turnerd2b1f351999-12-16 23:11:37 +000065 /*************************************************************************/
Werner Lemberg78575dc2000-06-12 19:36:41 +000066 /* */
67 /* <Function> */
68 /* TT_Get_Metrics */
69 /* */
70 /* <Description> */
David Turnerd2b1f351999-12-16 23:11:37 +000071 /* Returns the horizontal or vertical metrics in font units for a */
72 /* given glyph. The metrics are the left side bearing (resp. top */
73 /* side bearing) and advance width (resp. advance height). */
74 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000075 /* <Input> */
76 /* header :: A pointer to either the horizontal or vertical metrics */
77 /* structure. */
78 /* */
79 /* index :: The glyph index. */
80 /* */
81 /* <Output> */
82 /* bearing :: The bearing, either left side or top side. */
83 /* */
84 /* advance :: The advance width resp. advance height. */
85 /* */
86 /* <Note> */
87 /* This function will much probably move to another component in the */
88 /* near future, but I haven't decided which yet. */
89 /* */
David Turnerd2b1f351999-12-16 23:11:37 +000090 LOCAL_FUNC
91 void TT_Get_Metrics( TT_HoriHeader* header,
David Turnerf9b8dec2000-06-16 19:34:52 +000092 FT_UInt index,
93 FT_Short* bearing,
94 FT_UShort* advance )
David Turnerd2b1f351999-12-16 23:11:37 +000095 {
96 TT_LongMetrics* longs_m;
David Turnerf9b8dec2000-06-16 19:34:52 +000097 FT_UShort k = header->number_Of_HMetrics;
David Turnerd2b1f351999-12-16 23:11:37 +000098
99
100 if ( index < k )
101 {
102 longs_m = (TT_LongMetrics*)header->long_metrics + index;
103 *bearing = longs_m->bearing;
104 *advance = longs_m->advance;
105 }
106 else
107 {
108 *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k];
109 *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance;
110 }
111 }
112
113
114 /*************************************************************************/
Werner Lemberg78575dc2000-06-12 19:36:41 +0000115 /* */
Werner Lembergdcd2e142000-06-25 07:43:15 +0000116 /* Returns the horizontal metrics in font units for a given glyph. If */
117 /* `check' is true, take care of monospaced fonts by returning the */
118 /* advance width maximum. */
David Turnerd2b1f351999-12-16 23:11:37 +0000119 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000120 static
121 void Get_HMetrics( TT_Face face,
David Turnerf9b8dec2000-06-16 19:34:52 +0000122 FT_UInt index,
123 FT_Bool check,
124 FT_Short* lsb,
125 FT_UShort* aw )
David Turnerd2b1f351999-12-16 23:11:37 +0000126 {
127 TT_Get_Metrics( &face->horizontal, index, lsb, aw );
128
129 if ( check && face->postscript.isFixedPitch )
130 *aw = face->horizontal.advance_Width_Max;
131 }
132
133
134 /*************************************************************************/
Werner Lemberg78575dc2000-06-12 19:36:41 +0000135 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000136 /* Returns the advance width table for a given pixel size if it is */
137 /* found in the font's `hdmx' table (if any). */
138 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000139 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000140 FT_Byte* Get_Advance_Widths( TT_Face face,
141 FT_UShort ppem )
David Turnerd2b1f351999-12-16 23:11:37 +0000142 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000143 FT_UShort n;
David Turnerd2b1f351999-12-16 23:11:37 +0000144
145 for ( n = 0; n < face->hdmx.num_records; n++ )
146 if ( face->hdmx.records[n].ppem == ppem )
147 return face->hdmx.records[n].widths;
148
149 return NULL;
150 }
151
152
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000153#define cur_to_org( n, zone ) \
David Turnerf9b8dec2000-06-16 19:34:52 +0000154 MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( FT_Vector ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000155
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000156#define org_to_cur( n, zone ) \
David Turnerf9b8dec2000-06-16 19:34:52 +0000157 MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( FT_Vector ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000158
159
160 /*************************************************************************/
Werner Lemberg78575dc2000-06-12 19:36:41 +0000161 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000162 /* Translates an array of coordinates. */
163 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000164 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000165 void translate_array( FT_UInt n,
166 FT_Vector* coords,
167 FT_Pos delta_x,
168 FT_Pos delta_y )
David Turnerd2b1f351999-12-16 23:11:37 +0000169 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000170 FT_UInt k;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000171
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000172
David Turnerd2b1f351999-12-16 23:11:37 +0000173 if ( delta_x )
174 for ( k = 0; k < n; k++ )
175 coords[k].x += delta_x;
176
177 if ( delta_y )
178 for ( k = 0; k < n; k++ )
179 coords[k].y += delta_y;
180 }
181
182
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000183 static
184 void tt_prepare_zone( TT_GlyphZone* zone,
185 FT_GlyphLoad* load,
186 FT_UInt start_point,
187 FT_UInt start_contour )
David Turnerd2b1f351999-12-16 23:11:37 +0000188 {
David Turnerf0df85b2000-06-22 00:17:42 +0000189 zone->n_points = load->outline.n_points - start_point;
190 zone->n_contours = load->outline.n_contours - start_contour;
191 zone->org = load->extra_points + start_point;
192 zone->cur = load->outline.points + start_point;
193 zone->tags = (FT_Byte*)load->outline.tags + start_point;
194 zone->contours = (FT_UShort*)load->outline.contours + start_contour;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000195 }
David Turnerd2b1f351999-12-16 23:11:37 +0000196
197
David Turner8f43c712000-02-02 12:16:19 +0000198#undef IS_HINTED
Werner Lemberg78575dc2000-06-12 19:36:41 +0000199#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
200
David Turner8f43c712000-02-02 12:16:19 +0000201
David Turnerd2b1f351999-12-16 23:11:37 +0000202 /*************************************************************************/
203 /* */
David Turner90f68b72000-06-23 12:26:14 +0000204 /* The following functions are used by default with TrueType fonts. */
205 /* However, they can be replaced by alternatives if we need to support */
Werner Lemberga929ba92000-06-25 06:47:11 +0000206 /* TrueType-compressed formats (like MicroType) in the future. */
David Turnerd2b1f351999-12-16 23:11:37 +0000207 /* */
Werner Lemberga929ba92000-06-25 06:47:11 +0000208 /*************************************************************************/
David Turner90f68b72000-06-23 12:26:14 +0000209
210 static
211 FT_Error TT_Access_Glyph_Frame( TT_Loader* loader,
212 FT_UInt glyph_index,
213 FT_ULong offset,
214 FT_UInt byte_count )
215 {
216 FT_Error error;
217 FT_Stream stream = loader->stream;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000218
Werner Lemberga929ba92000-06-25 06:47:11 +0000219
220 /* the following line sets the `error' variable through macros! */
David Turner90f68b72000-06-23 12:26:14 +0000221 (void)( FILE_Seek( offset ) || ACCESS_Frame( byte_count ) );
Werner Lembergbd5ae402000-07-05 04:32:02 +0000222
David Turner90f68b72000-06-23 12:26:14 +0000223 FT_TRACE5(( "Glyph %ld\n", glyph_index ));
224 return error;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000225 }
David Turner90f68b72000-06-23 12:26:14 +0000226
227
David Turner90f68b72000-06-23 12:26:14 +0000228 static
Werner Lemberga929ba92000-06-25 06:47:11 +0000229 void TT_Forget_Glyph_Frame( TT_Loader* loader )
David Turner90f68b72000-06-23 12:26:14 +0000230 {
231 FT_Stream stream = loader->stream;
Werner Lemberga929ba92000-06-25 06:47:11 +0000232
233
David Turner90f68b72000-06-23 12:26:14 +0000234 FORGET_Frame();
Werner Lembergbd5ae402000-07-05 04:32:02 +0000235 }
David Turner90f68b72000-06-23 12:26:14 +0000236
237
David Turner90f68b72000-06-23 12:26:14 +0000238 static
239 FT_Error TT_Load_Glyph_Header( TT_Loader* loader )
240 {
241 FT_Stream stream = loader->stream;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000242
Werner Lemberga929ba92000-06-25 06:47:11 +0000243
David Turner90f68b72000-06-23 12:26:14 +0000244 loader->n_contours = GET_Short();
245
246 loader->bbox.xMin = GET_Short();
247 loader->bbox.yMin = GET_Short();
248 loader->bbox.xMax = GET_Short();
249 loader->bbox.yMax = GET_Short();
250
251 FT_TRACE5(( " # of contours: %d\n", loader->n_contours ));
252 FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin,
253 loader->bbox.xMax ));
254 FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin,
255 loader->bbox.yMax ));
Werner Lembergbd5ae402000-07-05 04:32:02 +0000256
David Turner90f68b72000-06-23 12:26:14 +0000257 return FT_Err_Ok;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000258 }
David Turner90f68b72000-06-23 12:26:14 +0000259
260
David Turnerd2b1f351999-12-16 23:11:37 +0000261 static
David Turner994d7742000-06-25 04:49:19 +0000262 FT_Error TT_Load_Simple_Glyph( TT_Loader* load )
David Turnerd2b1f351999-12-16 23:11:37 +0000263 {
David Turnerf0df85b2000-06-22 00:17:42 +0000264 FT_Error error;
David Turner994d7742000-06-25 04:49:19 +0000265 FT_Stream stream = load->stream;
266 FT_GlyphLoader* gloader = load->gloader;
267 FT_Int n_contours = load->n_contours;
David Turnerf0df85b2000-06-22 00:17:42 +0000268 FT_Outline* outline;
David Turnerc3128612000-06-23 05:02:13 +0000269 TT_Face face = (TT_Face)load->face;
270 TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph;
David Turnerf0df85b2000-06-22 00:17:42 +0000271 FT_UShort n_ins;
272 FT_Int n, n_points;
David Turnere49ab252000-05-16 23:44:38 +0000273
Werner Lemberg78575dc2000-06-12 19:36:41 +0000274
David Turnerf0df85b2000-06-22 00:17:42 +0000275 /* reading the contours endpoints & number of points */
276 {
277 short* cur = gloader->current.outline.contours;
278 short* limit = cur + n_contours;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000279
Werner Lemberga929ba92000-06-25 06:47:11 +0000280
David Turnerf0df85b2000-06-22 00:17:42 +0000281 for ( ; cur < limit; cur++ )
282 cur[0] = GET_UShort();
Werner Lembergbd5ae402000-07-05 04:32:02 +0000283
David Turnerf0df85b2000-06-22 00:17:42 +0000284 n_points = 0;
Werner Lemberga929ba92000-06-25 06:47:11 +0000285 if ( n_contours > 0 )
286 n_points = cur[-1] + 1;
David Turnerd2b1f351999-12-16 23:11:37 +0000287
Werner Lemberga929ba92000-06-25 06:47:11 +0000288 error = FT_GlyphLoader_Check_Points( gloader, n_points + 2, 0 );
289 if ( error )
290 goto Fail;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000291
David Turnerf0df85b2000-06-22 00:17:42 +0000292 outline = &gloader->current.outline;
293 }
294
Werner Lemberg78575dc2000-06-12 19:36:41 +0000295 /* reading the bytecode instructions */
David Turnerc3128612000-06-23 05:02:13 +0000296 slot->control_len = 0;
297 slot->control_data = 0;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000298
David Turnerd2b1f351999-12-16 23:11:37 +0000299 n_ins = GET_UShort();
300
Werner Lemberg1c0d4ac2000-06-06 20:41:48 +0000301 FT_TRACE5(( " Instructions size: %d\n", n_ins ));
David Turnerd2b1f351999-12-16 23:11:37 +0000302
303 if ( n_ins > face->max_profile.maxSizeOfInstructions )
304 {
305 FT_TRACE0(( "ERROR: Too many instructions!\n" ));
306 error = TT_Err_Too_Many_Ins;
307 goto Fail;
308 }
309
Werner Lemberg78575dc2000-06-12 19:36:41 +0000310 if ( stream->cursor + n_ins > stream->limit )
David Turnerd2b1f351999-12-16 23:11:37 +0000311 {
312 FT_TRACE0(( "ERROR: Instruction count mismatch!\n" ));
313 error = TT_Err_Too_Many_Ins;
314 goto Fail;
315 }
David Turnerd2b1f351999-12-16 23:11:37 +0000316
David Turner8f43c712000-02-02 12:16:19 +0000317#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberga929ba92000-06-25 06:47:11 +0000318
319 if ( ( load->load_flags &
David Turnerc3128612000-06-23 05:02:13 +0000320 ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 &&
321 load->instructions )
David Turner08fdac92000-02-21 16:01:33 +0000322 {
David Turnerc3128612000-06-23 05:02:13 +0000323 slot->control_len = n_ins;
324 slot->control_data = load->instructions;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000325
David Turnerc3128612000-06-23 05:02:13 +0000326 MEM_Copy( load->instructions, stream->cursor, n_ins );
David Turner08fdac92000-02-21 16:01:33 +0000327 }
Werner Lemberga929ba92000-06-25 06:47:11 +0000328
Werner Lemberg78575dc2000-06-12 19:36:41 +0000329#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
David Turnerd2b1f351999-12-16 23:11:37 +0000330
David Turner8f43c712000-02-02 12:16:19 +0000331 stream->cursor += n_ins;
David Turnere49ab252000-05-16 23:44:38 +0000332
Werner Lemberg78575dc2000-06-12 19:36:41 +0000333 /* reading the point tags */
David Turnerd2b1f351999-12-16 23:11:37 +0000334
David Turnere49ab252000-05-16 23:44:38 +0000335 {
David Turnerf0df85b2000-06-22 00:17:42 +0000336 FT_Byte* flag = (FT_Byte*)outline->tags;
David Turnerf9b8dec2000-06-16 19:34:52 +0000337 FT_Byte* limit = flag + n_points;
338 FT_Byte c, count;
David Turnere49ab252000-05-16 23:44:38 +0000339
Werner Lemberga929ba92000-06-25 06:47:11 +0000340
Werner Lemberg78575dc2000-06-12 19:36:41 +0000341 for ( ; flag < limit; flag++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000342 {
David Turner8f43c712000-02-02 12:16:19 +0000343 *flag = c = GET_Byte();
344 if ( c & 8 )
David Turnerd2b1f351999-12-16 23:11:37 +0000345 {
David Turner8f43c712000-02-02 12:16:19 +0000346 for ( count = GET_Byte(); count > 0; count-- )
347 *++flag = c;
David Turnerd2b1f351999-12-16 23:11:37 +0000348 }
349 }
350 }
351
Werner Lemberg78575dc2000-06-12 19:36:41 +0000352 /* reading the X coordinates */
David Turnere49ab252000-05-16 23:44:38 +0000353
David Turnerd2b1f351999-12-16 23:11:37 +0000354 {
David Turnerf0df85b2000-06-22 00:17:42 +0000355 FT_Vector* vec = outline->points;
David Turnerf9b8dec2000-06-16 19:34:52 +0000356 FT_Vector* limit = vec + n_points;
David Turnerf0df85b2000-06-22 00:17:42 +0000357 FT_Byte* flag = (FT_Byte*)outline->tags;
David Turnerf9b8dec2000-06-16 19:34:52 +0000358 FT_Pos x = 0;
David Turnere49ab252000-05-16 23:44:38 +0000359
Werner Lemberg78575dc2000-06-12 19:36:41 +0000360
David Turner8f43c712000-02-02 12:16:19 +0000361 for ( ; vec < limit; vec++, flag++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000362 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000363 FT_Pos y = 0;
David Turnere49ab252000-05-16 23:44:38 +0000364
Werner Lemberg78575dc2000-06-12 19:36:41 +0000365
David Turner8f43c712000-02-02 12:16:19 +0000366 if ( *flag & 2 )
367 {
368 y = GET_Byte();
Werner Lemberg78575dc2000-06-12 19:36:41 +0000369 if ( ( *flag & 16 ) == 0 )
370 y = -y;
David Turner8f43c712000-02-02 12:16:19 +0000371 }
Werner Lemberg78575dc2000-06-12 19:36:41 +0000372 else if ( ( *flag & 16 ) == 0 )
David Turner8f43c712000-02-02 12:16:19 +0000373 y = GET_Short();
David Turnere49ab252000-05-16 23:44:38 +0000374
David Turner8f43c712000-02-02 12:16:19 +0000375 x += y;
376 vec->x = x;
David Turnerd2b1f351999-12-16 23:11:37 +0000377 }
David Turnerd2b1f351999-12-16 23:11:37 +0000378 }
379
Werner Lemberg78575dc2000-06-12 19:36:41 +0000380 /* reading the Y coordinates */
David Turnerd2b1f351999-12-16 23:11:37 +0000381
David Turnerd2b1f351999-12-16 23:11:37 +0000382 {
David Turnerf0df85b2000-06-22 00:17:42 +0000383 FT_Vector* vec = gloader->current.outline.points;
David Turnerf9b8dec2000-06-16 19:34:52 +0000384 FT_Vector* limit = vec + n_points;
David Turnerf0df85b2000-06-22 00:17:42 +0000385 FT_Byte* flag = (FT_Byte*)outline->tags;
David Turnerf9b8dec2000-06-16 19:34:52 +0000386 FT_Pos x = 0;
David Turnere49ab252000-05-16 23:44:38 +0000387
Werner Lemberg78575dc2000-06-12 19:36:41 +0000388
David Turner8f43c712000-02-02 12:16:19 +0000389 for ( ; vec < limit; vec++, flag++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000390 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000391 FT_Pos y = 0;
David Turnere49ab252000-05-16 23:44:38 +0000392
Werner Lemberg78575dc2000-06-12 19:36:41 +0000393
David Turner8f43c712000-02-02 12:16:19 +0000394 if ( *flag & 4 )
395 {
396 y = GET_Byte();
Werner Lemberg78575dc2000-06-12 19:36:41 +0000397 if ( ( *flag & 32 ) == 0 )
398 y = -y;
David Turner8f43c712000-02-02 12:16:19 +0000399 }
Werner Lemberg78575dc2000-06-12 19:36:41 +0000400 else if ( ( *flag & 32 ) == 0 )
David Turner8f43c712000-02-02 12:16:19 +0000401 y = GET_Short();
David Turnere49ab252000-05-16 23:44:38 +0000402
David Turner8f43c712000-02-02 12:16:19 +0000403 x += y;
404 vec->y = x;
David Turnerd2b1f351999-12-16 23:11:37 +0000405 }
David Turnerd2b1f351999-12-16 23:11:37 +0000406 }
407
David Turnerc3128612000-06-23 05:02:13 +0000408 /* clear the touch tags */
409 for ( n = 0; n < n_points; n++ )
410 outline->tags[n] &= FT_Curve_Tag_On;
411
412 outline->n_points = n_points;
413 outline->n_contours = n_contours;
David Turnerc3128612000-06-23 05:02:13 +0000414
Werner Lembergbd5ae402000-07-05 04:32:02 +0000415 Fail:
David Turnerc3128612000-06-23 05:02:13 +0000416 return error;
417 }
418
419
David Turner90f68b72000-06-23 12:26:14 +0000420 static
David Turner994d7742000-06-25 04:49:19 +0000421 FT_Error TT_Load_Composite_Glyph( TT_Loader* loader )
David Turner90f68b72000-06-23 12:26:14 +0000422 {
423 FT_Error error;
Werner Lembergdcd2e142000-06-25 07:43:15 +0000424 FT_Stream stream = loader->stream;
425 FT_GlyphLoader* gloader = loader->gloader;
David Turner90f68b72000-06-23 12:26:14 +0000426 FT_SubGlyph* subglyph;
427 FT_UInt num_subglyphs;
428
Werner Lemberga929ba92000-06-25 06:47:11 +0000429
David Turner90f68b72000-06-23 12:26:14 +0000430 num_subglyphs = 0;
Werner Lemberga929ba92000-06-25 06:47:11 +0000431
David Turner90f68b72000-06-23 12:26:14 +0000432 do
433 {
434 FT_Fixed xx, xy, yy, yx;
435
Werner Lemberga929ba92000-06-25 06:47:11 +0000436
David Turner90f68b72000-06-23 12:26:14 +0000437 /* check that we can load a new subglyph */
Werner Lembergdcd2e142000-06-25 07:43:15 +0000438 error = FT_GlyphLoader_Check_Subglyphs( gloader, num_subglyphs + 1 );
Werner Lemberga929ba92000-06-25 06:47:11 +0000439 if ( error )
440 goto Fail;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000441
David Turner90f68b72000-06-23 12:26:14 +0000442 subglyph = gloader->current.subglyphs + num_subglyphs;
443
444 subglyph->arg1 = subglyph->arg2 = 0;
445
446 subglyph->flags = GET_UShort();
447 subglyph->index = GET_UShort();
448
449 /* read arguments */
450 if ( subglyph->flags & ARGS_ARE_WORDS )
451 {
452 subglyph->arg1 = GET_Short();
453 subglyph->arg2 = GET_Short();
454 }
455 else
456 {
457 subglyph->arg1 = GET_Char();
458 subglyph->arg2 = GET_Char();
459 }
460
461 /* read transform */
462 xx = yy = 0x10000L;
463 xy = yx = 0;
464
465 if ( subglyph->flags & WE_HAVE_A_SCALE )
466 {
467 xx = (FT_Fixed)GET_Short() << 2;
468 yy = xx;
469 }
470 else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
471 {
472 xx = (FT_Fixed)GET_Short() << 2;
473 yy = (FT_Fixed)GET_Short() << 2;
474 }
475 else if ( subglyph->flags & WE_HAVE_A_2X2 )
476 {
477 xx = (FT_Fixed)GET_Short() << 2;
478 xy = (FT_Fixed)GET_Short() << 2;
479 yx = (FT_Fixed)GET_Short() << 2;
480 yy = (FT_Fixed)GET_Short() << 2;
481 }
482
483 subglyph->transform.xx = xx;
484 subglyph->transform.xy = xy;
485 subglyph->transform.yx = yx;
486 subglyph->transform.yy = yy;
487
488 num_subglyphs++;
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000489
Werner Lembergdcd2e142000-06-25 07:43:15 +0000490 } while ( subglyph->flags & MORE_COMPONENTS );
David Turner90f68b72000-06-23 12:26:14 +0000491
492 gloader->current.num_subglyphs = num_subglyphs;
493
494#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
495 {
496 /* we must undo the ACCESS_Frame in order to point to the */
497 /* composite instructions, if we find some. */
498 /* we will process them later... */
499 /* */
500 loader->ins_pos = FILE_Pos() + stream->cursor - stream->limit;
501 }
502#endif
503
504 Fail:
505 return error;
506 }
507
David Turnerc3128612000-06-23 05:02:13 +0000508
David Turner994d7742000-06-25 04:49:19 +0000509 LOCAL_FUNC
510 void TT_Init_Glyph_Loading( TT_Face face )
511 {
512 face->access_glyph_frame = TT_Access_Glyph_Frame;
513 face->read_glyph_header = TT_Load_Glyph_Header;
514 face->read_simple_glyph = TT_Load_Simple_Glyph;
515 face->read_composite_glyph = TT_Load_Composite_Glyph;
516 face->forget_glyph_frame = TT_Forget_Glyph_Frame;
517 }
518
David Turnerc3128612000-06-23 05:02:13 +0000519
520 /*************************************************************************/
521 /* */
522 /* <Function> */
523 /* TT_Process_Simple_Glyph */
524 /* */
525 /* <Description> */
526 /* Once a simple glyph has been loaded, it needs to be processed. */
527 /* Usually, this means scaling and hinting through bytecode */
Werner Lemberga929ba92000-06-25 06:47:11 +0000528 /* interpretation. */
David Turnerc3128612000-06-23 05:02:13 +0000529 /* */
530 static
Werner Lemberga929ba92000-06-25 06:47:11 +0000531 FT_Error TT_Process_Simple_Glyph( TT_Loader* load,
532 FT_Bool debug )
David Turnerc3128612000-06-23 05:02:13 +0000533 {
534 FT_GlyphLoader* gloader = load->gloader;
535 FT_Outline* outline = &gloader->current.outline;
536 FT_UInt n_points = outline->n_points;
537 FT_UInt n_ins;
538 TT_GlyphZone* zone = &load->zone;
539 FT_Error error = FT_Err_Ok;
540
Werner Lemberga929ba92000-06-25 06:47:11 +0000541
David Turnerc3128612000-06-23 05:02:13 +0000542 n_ins = load->glyph->control_len;
543
Werner Lemberg78575dc2000-06-12 19:36:41 +0000544 /* add shadow points */
David Turnere49ab252000-05-16 23:44:38 +0000545
David Turnerd2b1f351999-12-16 23:11:37 +0000546 /* Now add the two shadow points at n and n + 1. */
547 /* We need the left side bearing and advance width. */
548
David Turner8f43c712000-02-02 12:16:19 +0000549 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000550 FT_Vector* pp1;
551 FT_Vector* pp2;
David Turnere49ab252000-05-16 23:44:38 +0000552
Werner Lemberga929ba92000-06-25 06:47:11 +0000553
David Turner8f43c712000-02-02 12:16:19 +0000554 /* pp1 = xMin - lsb */
David Turnerf0df85b2000-06-22 00:17:42 +0000555 pp1 = outline->points + n_points;
David Turner8f43c712000-02-02 12:16:19 +0000556 pp1->x = load->bbox.xMin - load->left_bearing;
557 pp1->y = 0;
David Turnere49ab252000-05-16 23:44:38 +0000558
David Turner8f43c712000-02-02 12:16:19 +0000559 /* pp2 = pp1 + aw */
560 pp2 = pp1 + 1;
561 pp2->x = pp1->x + load->advance;
562 pp2->y = 0;
David Turnere49ab252000-05-16 23:44:38 +0000563
David Turnerf0df85b2000-06-22 00:17:42 +0000564 outline->tags[n_points ] = 0;
565 outline->tags[n_points + 1] = 0;
David Turner8f43c712000-02-02 12:16:19 +0000566 }
Werner Lemberg78575dc2000-06-12 19:36:41 +0000567
David Turnerd2b1f351999-12-16 23:11:37 +0000568 /* Note that we return two more points that are not */
569 /* part of the glyph outline. */
570
Werner Lembergdcd2e142000-06-25 07:43:15 +0000571 n_points += 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000572
David Turnerf0df85b2000-06-22 00:17:42 +0000573 /* set up zone for hinting */
574 tt_prepare_zone( zone, &gloader->current, 0, 0 );
David Turnerd2b1f351999-12-16 23:11:37 +0000575
David Turnerf0df85b2000-06-22 00:17:42 +0000576 /* eventually scale the glyph */
Werner Lemberga929ba92000-06-25 06:47:11 +0000577 if ( !( load->load_flags & FT_LOAD_NO_SCALE ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000578 {
David Turnerf0df85b2000-06-22 00:17:42 +0000579 FT_Vector* vec = zone->cur;
580 FT_Vector* limit = vec + n_points;
David Turnerc3128612000-06-23 05:02:13 +0000581 FT_Fixed x_scale = load->size->metrics.x_scale;
582 FT_Fixed y_scale = load->size->metrics.y_scale;
David Turner8f43c712000-02-02 12:16:19 +0000583
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000584
David Turnerd2b1f351999-12-16 23:11:37 +0000585 /* first scale the glyph points */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000586 for ( ; vec < limit; vec++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000587 {
David Turner8f43c712000-02-02 12:16:19 +0000588 vec->x = FT_MulFix( vec->x, x_scale );
589 vec->y = FT_MulFix( vec->y, y_scale );
David Turnerd2b1f351999-12-16 23:11:37 +0000590 }
David Turnerf0df85b2000-06-22 00:17:42 +0000591 }
David Turnerd2b1f351999-12-16 23:11:37 +0000592
David Turnerf0df85b2000-06-22 00:17:42 +0000593 cur_to_org( n_points, zone );
Werner Lemberg78575dc2000-06-12 19:36:41 +0000594
David Turnerf0df85b2000-06-22 00:17:42 +0000595 /* eventually hint the glyph */
Werner Lemberga929ba92000-06-25 06:47:11 +0000596 if ( IS_HINTED( load->load_flags ) )
David Turnerf0df85b2000-06-22 00:17:42 +0000597 {
598 FT_Pos x = zone->org[n_points-2].x;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000599
Werner Lemberga929ba92000-06-25 06:47:11 +0000600
David Turnerf0df85b2000-06-22 00:17:42 +0000601 x = ( ( x + 32 ) & -64 ) - x;
602 translate_array( n_points, zone->org, x, 0 );
David Turnerd2b1f351999-12-16 23:11:37 +0000603
David Turnerf0df85b2000-06-22 00:17:42 +0000604 org_to_cur( n_points, zone );
David Turnerd2b1f351999-12-16 23:11:37 +0000605
David Turnerf0df85b2000-06-22 00:17:42 +0000606 zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64;
David Turnerd2b1f351999-12-16 23:11:37 +0000607
David Turner8f43c712000-02-02 12:16:19 +0000608#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberga929ba92000-06-25 06:47:11 +0000609
David Turnerf0df85b2000-06-22 00:17:42 +0000610 /* now consider hinting */
611 if ( n_ins > 0 )
612 {
David Turnerc3128612000-06-23 05:02:13 +0000613 error = TT_Set_CodeRange( load->exec, tt_coderange_glyph,
614 load->exec->glyphIns, n_ins );
Werner Lemberga929ba92000-06-25 06:47:11 +0000615 if ( error )
616 goto Exit;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000617
David Turnerf0df85b2000-06-22 00:17:42 +0000618 load->exec->is_composite = FALSE;
Werner Lemberga929ba92000-06-25 06:47:11 +0000619 load->exec->pedantic_hinting = (FT_Bool)( load->load_flags &
620 FT_LOAD_PEDANTIC );
David Turnerf0df85b2000-06-22 00:17:42 +0000621 load->exec->pts = *zone;
622 load->exec->pts.n_points += 2;
David Turnerd2b1f351999-12-16 23:11:37 +0000623
David Turnerf0df85b2000-06-22 00:17:42 +0000624 error = TT_Run_Context( load->exec, debug );
625 if ( error && load->exec->pedantic_hinting )
David Turnerc3128612000-06-23 05:02:13 +0000626 goto Exit;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000627
David Turnerc3128612000-06-23 05:02:13 +0000628 error = FT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */
David Turnerd2b1f351999-12-16 23:11:37 +0000629 }
Werner Lemberga929ba92000-06-25 06:47:11 +0000630
David Turnerf0df85b2000-06-22 00:17:42 +0000631#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
Werner Lemberga929ba92000-06-25 06:47:11 +0000632
David Turnerd2b1f351999-12-16 23:11:37 +0000633 }
634
635 /* save glyph phantom points */
David Turner8f43c712000-02-02 12:16:19 +0000636 if ( !load->preserve_pps )
David Turnerd2b1f351999-12-16 23:11:37 +0000637 {
David Turner8f43c712000-02-02 12:16:19 +0000638 load->pp1 = zone->cur[n_points - 2];
639 load->pp2 = zone->cur[n_points - 1];
David Turnerd2b1f351999-12-16 23:11:37 +0000640 }
641
David Turnerc3128612000-06-23 05:02:13 +0000642 Exit:
David Turnerd2b1f351999-12-16 23:11:37 +0000643 return error;
644 }
645
646
647 /*************************************************************************/
648 /* */
649 /* <Function> */
David Turner8f43c712000-02-02 12:16:19 +0000650 /* load_truetype_glyph */
David Turnerd2b1f351999-12-16 23:11:37 +0000651 /* */
652 /* <Description> */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000653 /* Loads a given truetype glyph. Handles composites and uses a */
654 /* TT_Loader object. */
David Turnerd2b1f351999-12-16 23:11:37 +0000655 /* */
656 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000657 FT_Error load_truetype_glyph( TT_Loader* loader,
658 FT_UInt glyph_index )
David Turnerd2b1f351999-12-16 23:11:37 +0000659 {
David Turnerf0df85b2000-06-22 00:17:42 +0000660 FT_Stream stream = loader->stream;
661 FT_Error error;
David Turnerc3128612000-06-23 05:02:13 +0000662 TT_Face face = (TT_Face)loader->face;
David Turnerf0df85b2000-06-22 00:17:42 +0000663 FT_ULong offset;
David Turnerc3128612000-06-23 05:02:13 +0000664 FT_Int contours_count;
David Turnerf0df85b2000-06-22 00:17:42 +0000665 FT_UInt index, num_points, num_contours, count;
666 FT_Fixed x_scale, y_scale;
667 FT_ULong ins_offset;
668 FT_GlyphLoader* gloader = loader->gloader;
David Turner90f68b72000-06-23 12:26:14 +0000669 FT_Bool opened_frame = 0;
David Turnere49ab252000-05-16 23:44:38 +0000670
Werner Lemberg78575dc2000-06-12 19:36:41 +0000671
David Turner8f43c712000-02-02 12:16:19 +0000672 /* check glyph index */
David Turnered7f62a2000-03-28 11:19:28 +0000673 index = glyph_index;
David Turnerf9b8dec2000-06-16 19:34:52 +0000674 if ( index >= (FT_UInt)face->root.num_glyphs )
David Turnerd2b1f351999-12-16 23:11:37 +0000675 {
David Turner8f43c712000-02-02 12:16:19 +0000676 error = TT_Err_Invalid_Glyph_Index;
David Turner90f68b72000-06-23 12:26:14 +0000677 goto Exit;
David Turnerd2b1f351999-12-16 23:11:37 +0000678 }
679
David Turner861ba622000-02-15 12:54:51 +0000680 loader->glyph_index = glyph_index;
David Turnerd2b1f351999-12-16 23:11:37 +0000681 num_contours = 0;
David Turner8f43c712000-02-02 12:16:19 +0000682 num_points = 0;
683 ins_offset = 0;
David Turnere49ab252000-05-16 23:44:38 +0000684
Werner Lemberg78575dc2000-06-12 19:36:41 +0000685 x_scale = 0x10000L;
686 y_scale = 0x10000L;
687 if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
David Turnerd2b1f351999-12-16 23:11:37 +0000688 {
David Turnerc3128612000-06-23 05:02:13 +0000689 x_scale = loader->size->metrics.x_scale;
690 y_scale = loader->size->metrics.y_scale;
David Turner8f43c712000-02-02 12:16:19 +0000691 }
David Turnerd2b1f351999-12-16 23:11:37 +0000692
David Turner8f43c712000-02-02 12:16:19 +0000693 /* get horizontal metrics */
694 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000695 FT_Short left_bearing;
696 FT_UShort advance_width;
David Turnerd2b1f351999-12-16 23:11:37 +0000697
Werner Lemberg78575dc2000-06-12 19:36:41 +0000698
David Turner71ec10e2000-02-10 16:09:35 +0000699 Get_HMetrics( face, index,
David Turnerf9b8dec2000-06-16 19:34:52 +0000700 (FT_Bool)!(loader->load_flags &
Werner Lembergdcd2e142000-06-25 07:43:15 +0000701 FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH),
David Turner8f43c712000-02-02 12:16:19 +0000702 &left_bearing,
703 &advance_width );
David Turnerd2b1f351999-12-16 23:11:37 +0000704
David Turner8f43c712000-02-02 12:16:19 +0000705 loader->left_bearing = left_bearing;
706 loader->advance = advance_width;
707 }
David Turnerd2b1f351999-12-16 23:11:37 +0000708
David Turner8f43c712000-02-02 12:16:19 +0000709 offset = face->glyph_locations[index];
710 count = 0;
David Turnere49ab252000-05-16 23:44:38 +0000711
David Turnerf9b8dec2000-06-16 19:34:52 +0000712 if ( index < (FT_UInt)face->num_locations - 1 )
Werner Lemberg78575dc2000-06-12 19:36:41 +0000713 count = face->glyph_locations[index + 1] - offset;
David Turnerd2b1f351999-12-16 23:11:37 +0000714
Werner Lemberg78575dc2000-06-12 19:36:41 +0000715 if ( count == 0 )
David Turner8f43c712000-02-02 12:16:19 +0000716 {
717 /* as described by Frederic Loyer, these are spaces, and */
718 /* not the unknown glyph. */
719 loader->bbox.xMin = 0;
720 loader->bbox.xMax = 0;
721 loader->bbox.yMin = 0;
722 loader->bbox.yMax = 0;
David Turnerd2b1f351999-12-16 23:11:37 +0000723
David Turner8f43c712000-02-02 12:16:19 +0000724 loader->pp1.x = 0;
725 loader->pp2.x = loader->advance;
David Turnerd2b1f351999-12-16 23:11:37 +0000726
Werner Lemberg78575dc2000-06-12 19:36:41 +0000727 if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
David Turner8f43c712000-02-02 12:16:19 +0000728 loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
David Turnerd2b1f351999-12-16 23:11:37 +0000729
David Turner8f43c712000-02-02 12:16:19 +0000730#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lembergdcd2e142000-06-25 07:43:15 +0000731
Werner Lemberg78575dc2000-06-12 19:36:41 +0000732 if ( loader->exec )
David Turner7bb7fed2000-02-28 11:23:36 +0000733 loader->exec->glyphSize = 0;
Werner Lembergdcd2e142000-06-25 07:43:15 +0000734
David Turner8f43c712000-02-02 12:16:19 +0000735#endif
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000736
David Turner90f68b72000-06-23 12:26:14 +0000737 error = FT_Err_Ok;
738 goto Exit;
David Turner8f43c712000-02-02 12:16:19 +0000739 }
David Turnerd2b1f351999-12-16 23:11:37 +0000740
David Turner8f43c712000-02-02 12:16:19 +0000741 offset = loader->glyf_offset + offset;
David Turnerd2b1f351999-12-16 23:11:37 +0000742
David Turner90f68b72000-06-23 12:26:14 +0000743 /* access glyph frame */
David Turner994d7742000-06-25 04:49:19 +0000744 error = face->access_glyph_frame( loader, glyph_index, offset, count );
Werner Lemberga929ba92000-06-25 06:47:11 +0000745 if ( error )
746 goto Exit;
David Turner90f68b72000-06-23 12:26:14 +0000747
748 opened_frame = 1;
749
David Turner8f43c712000-02-02 12:16:19 +0000750 /* read first glyph header */
David Turner994d7742000-06-25 04:49:19 +0000751 error = face->read_glyph_header( loader );
Werner Lemberga929ba92000-06-25 06:47:11 +0000752 if ( error )
753 goto Fail;
David Turnerd2b1f351999-12-16 23:11:37 +0000754
David Turner90f68b72000-06-23 12:26:14 +0000755 contours_count = loader->n_contours;
David Turnerd2b1f351999-12-16 23:11:37 +0000756
David Turner8f43c712000-02-02 12:16:19 +0000757 count -= 10;
David Turnerd2b1f351999-12-16 23:11:37 +0000758
David Turner8f43c712000-02-02 12:16:19 +0000759 loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
760 loader->pp1.y = 0;
761 loader->pp2.x = loader->pp1.x + loader->advance;
762 loader->pp2.y = 0;
David Turnere49ab252000-05-16 23:44:38 +0000763
Werner Lemberg78575dc2000-06-12 19:36:41 +0000764 if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
David Turner8f43c712000-02-02 12:16:19 +0000765 {
766 loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
767 loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
768 }
David Turnerd2b1f351999-12-16 23:11:37 +0000769
Werner Lemberg78575dc2000-06-12 19:36:41 +0000770 /***********************************************************************/
771 /***********************************************************************/
772 /***********************************************************************/
David Turnerd2b1f351999-12-16 23:11:37 +0000773
Werner Lemberg78575dc2000-06-12 19:36:41 +0000774 /* if it is a simple glyph, load it */
775
776 if ( contours_count >= 0 )
David Turner8f43c712000-02-02 12:16:19 +0000777 {
David Turnerf0df85b2000-06-22 00:17:42 +0000778 /* check that we can add the contours to the glyph */
779 error = FT_GlyphLoader_Check_Points( gloader, 0, contours_count );
Werner Lemberga929ba92000-06-25 06:47:11 +0000780 if ( error )
781 goto Fail;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000782
David Turner994d7742000-06-25 04:49:19 +0000783 error = face->read_simple_glyph( loader );
Werner Lemberga929ba92000-06-25 06:47:11 +0000784 if ( error )
785 goto Fail;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000786
David Turner8f43c712000-02-02 12:16:19 +0000787#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000788
David Turnerc3128612000-06-23 05:02:13 +0000789 {
790 TT_Size size = (TT_Size)loader->size;
Werner Lembergdcd2e142000-06-25 07:43:15 +0000791
792
David Turnerc3128612000-06-23 05:02:13 +0000793 error = TT_Process_Simple_Glyph( loader,
794 (FT_Bool)( size && size->debug ) );
795 }
Werner Lembergdcd2e142000-06-25 07:43:15 +0000796
David Turner8f43c712000-02-02 12:16:19 +0000797#else
Werner Lembergdcd2e142000-06-25 07:43:15 +0000798
David Turnerc3128612000-06-23 05:02:13 +0000799 error = Process_Simple_Glyph( loader, 0 );
Werner Lembergdcd2e142000-06-25 07:43:15 +0000800
David Turnere49ab252000-05-16 23:44:38 +0000801#endif
Werner Lembergdcd2e142000-06-25 07:43:15 +0000802
803 if ( error )
804 goto Fail;
David Turnerf0df85b2000-06-22 00:17:42 +0000805
806 FT_GlyphLoader_Add( gloader );
David Turnerd2b1f351999-12-16 23:11:37 +0000807
David Turner8f43c712000-02-02 12:16:19 +0000808 /* Note: We could have put the simple loader source there */
809 /* but the code is fat enough already :-) */
David Turner8f43c712000-02-02 12:16:19 +0000810 }
David Turner8f43c712000-02-02 12:16:19 +0000811
Werner Lemberg78575dc2000-06-12 19:36:41 +0000812 /***********************************************************************/
813 /***********************************************************************/
814 /***********************************************************************/
815
816 /* otherwise, load a composite! */
817 else
David Turner8f43c712000-02-02 12:16:19 +0000818 {
David Turnerc3128612000-06-23 05:02:13 +0000819 TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph;
820 FT_UInt start_point, start_contour;
David Turnerc6a92202000-07-04 18:12:13 +0000821 FT_ULong ins_pos; /* position of composite instructions, if any */
Werner Lemberga929ba92000-06-25 06:47:11 +0000822
Werner Lembergbd5ae402000-07-05 04:32:02 +0000823
David Turner8f43c712000-02-02 12:16:19 +0000824 /* for each subglyph, read composite header */
David Turnerf0df85b2000-06-22 00:17:42 +0000825 start_point = gloader->base.outline.n_points;
826 start_contour = gloader->base.outline.n_contours;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000827
David Turner994d7742000-06-25 04:49:19 +0000828 error = face->read_composite_glyph( loader );
Werner Lemberga929ba92000-06-25 06:47:11 +0000829 if ( error )
830 goto Fail;
David Turnered7f62a2000-03-28 11:19:28 +0000831
David Turnerc6a92202000-07-04 18:12:13 +0000832 ins_pos = loader->ins_pos;
David Turner994d7742000-06-25 04:49:19 +0000833 face->forget_glyph_frame( loader );
David Turner90f68b72000-06-23 12:26:14 +0000834 opened_frame = 0;
835
David Turnered7f62a2000-03-28 11:19:28 +0000836 /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000837 /* `as is' in the glyph slot (the client application will be */
838 /* responsible for interpreting this data)... */
839 /* */
David Turnered7f62a2000-03-28 11:19:28 +0000840 if ( loader->load_flags & FT_LOAD_NO_RECURSE )
841 {
David Turnered7f62a2000-03-28 11:19:28 +0000842 /* set up remaining glyph fields */
David Turnerf0df85b2000-06-22 00:17:42 +0000843 FT_GlyphLoader_Add( gloader );
Werner Lembergbd5ae402000-07-05 04:32:02 +0000844
David Turnerf0df85b2000-06-22 00:17:42 +0000845 glyph->num_subglyphs = gloader->base.num_subglyphs;
David Turner3475e7f2000-05-17 20:56:01 +0000846 glyph->format = ft_glyph_format_composite;
David Turnerf0df85b2000-06-22 00:17:42 +0000847 glyph->subglyphs = gloader->base.subglyphs;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000848
David Turner90f68b72000-06-23 12:26:14 +0000849 goto Exit;
David Turnered7f62a2000-03-28 11:19:28 +0000850 }
851
David Turner8f43c712000-02-02 12:16:19 +0000852 /*********************************************************************/
Werner Lembergdcd2e142000-06-25 07:43:15 +0000853 /*********************************************************************/
854 /*********************************************************************/
855
856 /* Now, read each subglyph independently. */
David Turner8f43c712000-02-02 12:16:19 +0000857 {
David Turnerc3128612000-06-23 05:02:13 +0000858 FT_Int n, num_base_points, num_new_points;
Werner Lembergdcd2e142000-06-25 07:43:15 +0000859 FT_SubGlyph* subglyph = 0;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000860
David Turnerc3128612000-06-23 05:02:13 +0000861 FT_UInt num_subglyphs = gloader->current.num_subglyphs;
862 FT_UInt num_base_subgs = gloader->base.num_subglyphs;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000863
David Turnerc3128612000-06-23 05:02:13 +0000864
David Turnerf0df85b2000-06-22 00:17:42 +0000865 FT_GlyphLoader_Add( gloader );
Werner Lembergbd5ae402000-07-05 04:32:02 +0000866
David Turner74abee82000-06-27 23:31:53 +0000867 for ( n = 0; n < (FT_Int)num_subglyphs; n++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000868 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000869 FT_Vector pp1, pp2;
870 FT_Pos x, y;
David Turnere49ab252000-05-16 23:44:38 +0000871
Werner Lembergdcd2e142000-06-25 07:43:15 +0000872
Werner Lemberga929ba92000-06-25 06:47:11 +0000873 /* Each time we call load_truetype_glyph in this loop, the */
874 /* value of `gloader.base.subglyphs' can change due to table */
875 /* reallocations. We thus need to recompute the subglyph */
876 /* pointer on each iteration. */
David Turnerf0df85b2000-06-22 00:17:42 +0000877 subglyph = gloader->base.subglyphs + num_base_subgs + n;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000878
David Turner8f43c712000-02-02 12:16:19 +0000879 pp1 = loader->pp1;
880 pp2 = loader->pp2;
David Turnerd2b1f351999-12-16 23:11:37 +0000881
David Turnerf0df85b2000-06-22 00:17:42 +0000882 num_base_points = gloader->base.outline.n_points;
David Turnere49ab252000-05-16 23:44:38 +0000883
David Turner8f43c712000-02-02 12:16:19 +0000884 error = load_truetype_glyph( loader, subglyph->index );
Werner Lemberg78575dc2000-06-12 19:36:41 +0000885 if ( error )
886 goto Fail;
David Turner3475e7f2000-05-17 20:56:01 +0000887
David Turnerf0df85b2000-06-22 00:17:42 +0000888 subglyph = gloader->base.subglyphs + num_base_subgs + n;
889
David Turner7bb7fed2000-02-28 11:23:36 +0000890 if ( subglyph->flags & USE_MY_METRICS )
891 {
892 pp1 = loader->pp1;
893 pp2 = loader->pp2;
894 }
895 else
David Turnerd2b1f351999-12-16 23:11:37 +0000896 {
David Turner8f43c712000-02-02 12:16:19 +0000897 loader->pp1 = pp1;
898 loader->pp2 = pp2;
David Turnerd2b1f351999-12-16 23:11:37 +0000899 }
David Turnere49ab252000-05-16 23:44:38 +0000900
Werner Lembergdcd2e142000-06-25 07:43:15 +0000901 num_points = gloader->base.outline.n_points;
David Turnere49ab252000-05-16 23:44:38 +0000902
David Turner8f43c712000-02-02 12:16:19 +0000903 num_new_points = num_points - num_base_points;
David Turnere49ab252000-05-16 23:44:38 +0000904
David Turner8f43c712000-02-02 12:16:19 +0000905 /* now perform the transform required for this subglyph */
David Turnere49ab252000-05-16 23:44:38 +0000906
David Turner8f43c712000-02-02 12:16:19 +0000907 if ( subglyph->flags & ( WE_HAVE_A_SCALE |
908 WE_HAVE_AN_XY_SCALE |
909 WE_HAVE_A_2X2 ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000910 {
Werner Lemberga929ba92000-06-25 06:47:11 +0000911 FT_Vector* cur = gloader->base.outline.points +
912 num_base_points;
913 FT_Vector* org = gloader->base.extra_points +
914 num_base_points;
David Turnerf9b8dec2000-06-16 19:34:52 +0000915 FT_Vector* limit = cur + num_new_points;
David Turnerd2b1f351999-12-16 23:11:37 +0000916
Werner Lembergdcd2e142000-06-25 07:43:15 +0000917
David Turner8f43c712000-02-02 12:16:19 +0000918 for ( ; cur < limit; cur++, org++ )
David Turnerd2b1f351999-12-16 23:11:37 +0000919 {
David Turnerf0df85b2000-06-22 00:17:42 +0000920 FT_Vector_Transform( cur, &subglyph->transform );
921 FT_Vector_Transform( org, &subglyph->transform );
David Turnerd2b1f351999-12-16 23:11:37 +0000922 }
923 }
924
David Turnerd2b1f351999-12-16 23:11:37 +0000925 /* apply offset */
926
Werner Lemberg78575dc2000-06-12 19:36:41 +0000927 if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000928 {
David Turner74abee82000-06-27 23:31:53 +0000929 FT_UInt k = subglyph->arg1;
David Turnerf0df85b2000-06-22 00:17:42 +0000930 FT_UInt l = subglyph->arg2;
931 FT_Vector* p1;
932 FT_Vector* p2;
David Turnerd2b1f351999-12-16 23:11:37 +0000933
Werner Lembergdeb4e982000-06-29 03:14:25 +0000934
David Turner74abee82000-06-27 23:31:53 +0000935 if ( start_point + k >= (FT_UInt)num_base_points ||
David Turnerf0df85b2000-06-22 00:17:42 +0000936 l >= (FT_UInt)num_new_points )
David Turnerd2b1f351999-12-16 23:11:37 +0000937 {
938 error = TT_Err_Invalid_Composite;
939 goto Fail;
940 }
941
David Turnere49ab252000-05-16 23:44:38 +0000942 l += num_base_points;
943
David Turnerf0df85b2000-06-22 00:17:42 +0000944 p1 = gloader->base.outline.points + start_point + k;
945 p2 = gloader->base.outline.points + start_point + l;
Werner Lembergbd5ae402000-07-05 04:32:02 +0000946
David Turnerf0df85b2000-06-22 00:17:42 +0000947 x = p1->x - p2->x;
948 y = p1->y - p2->y;
David Turnerd2b1f351999-12-16 23:11:37 +0000949 }
950 else
951 {
David Turner8f43c712000-02-02 12:16:19 +0000952 x = subglyph->arg1;
953 y = subglyph->arg2;
David Turnerd2b1f351999-12-16 23:11:37 +0000954
Werner Lemberg78575dc2000-06-12 19:36:41 +0000955 if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000956 {
David Turner8f43c712000-02-02 12:16:19 +0000957 x = FT_MulFix( x, x_scale );
958 y = FT_MulFix( y, y_scale );
David Turnere49ab252000-05-16 23:44:38 +0000959
David Turner8f43c712000-02-02 12:16:19 +0000960 if ( subglyph->flags & ROUND_XY_TO_GRID )
Werner Lemberg78575dc2000-06-12 19:36:41 +0000961 {
962 x = ( x + 32 ) & -64;
963 y = ( y + 32 ) & -64;
964 }
David Turnerd2b1f351999-12-16 23:11:37 +0000965 }
966 }
967
David Turner8f43c712000-02-02 12:16:19 +0000968 translate_array( num_new_points, loader->zone.cur, x, y );
969 cur_to_org( num_new_points, &loader->zone );
David Turnerd2b1f351999-12-16 23:11:37 +0000970 }
David Turnere49ab252000-05-16 23:44:38 +0000971
Werner Lembergdcd2e142000-06-25 07:43:15 +0000972 /*******************************************************************/
973 /*******************************************************************/
974 /*******************************************************************/
David Turnerd2b1f351999-12-16 23:11:37 +0000975
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000976 /* we have finished loading all sub-glyphs; now, look for */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000977 /* instructions for this composite! */
David Turnerd2b1f351999-12-16 23:11:37 +0000978
David Turner8f43c712000-02-02 12:16:19 +0000979#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberg78575dc2000-06-12 19:36:41 +0000980
Werner Lemberg78575dc2000-06-12 19:36:41 +0000981 if ( num_subglyphs > 0 &&
982 loader->exec &&
David Turnerc6a92202000-07-04 18:12:13 +0000983 ins_pos > 0 &&
Werner Lemberg78575dc2000-06-12 19:36:41 +0000984 subglyph->flags & WE_HAVE_INSTR )
David Turner8f43c712000-02-02 12:16:19 +0000985 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000986 FT_UShort n_ins;
David Turner8f43c712000-02-02 12:16:19 +0000987 TT_ExecContext exec = loader->exec;
David Turnerf9b8dec2000-06-16 19:34:52 +0000988 TT_GlyphZone* pts;
989 FT_Vector* pp1;
David Turnere49ab252000-05-16 23:44:38 +0000990
Werner Lemberg78575dc2000-06-12 19:36:41 +0000991
David Turner8f43c712000-02-02 12:16:19 +0000992 /* read size of instructions */
David Turnerc6a92202000-07-04 18:12:13 +0000993 if ( FILE_Seek( ins_pos ) ||
994 READ_UShort( n_ins ) )
Werner Lemberg78575dc2000-06-12 19:36:41 +0000995 goto Fail;
Werner Lemberg1c0d4ac2000-06-06 20:41:48 +0000996 FT_TRACE5(( " Instructions size = %d\n", n_ins ));
David Turnere49ab252000-05-16 23:44:38 +0000997
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000998 /* in some fonts? */
Werner Lemberga929ba92000-06-25 06:47:11 +0000999 if ( n_ins == 0xFFFF )
David Turnerc3128612000-06-23 05:02:13 +00001000 n_ins = 0;
1001
David Turner8f43c712000-02-02 12:16:19 +00001002 /* check it */
1003 if ( n_ins > face->max_profile.maxSizeOfInstructions )
1004 {
David Turnerc3128612000-06-23 05:02:13 +00001005 FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n",
1006 n_ins, subglyph->index ));
David Turner8f43c712000-02-02 12:16:19 +00001007 return TT_Err_Too_Many_Ins;
1008 }
David Turnere49ab252000-05-16 23:44:38 +00001009
David Turner8f43c712000-02-02 12:16:19 +00001010 /* read the instructions */
1011 if ( FILE_Read( exec->glyphIns, n_ins ) )
1012 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00001013
David Turnerc3128612000-06-23 05:02:13 +00001014 glyph->control_data = exec->glyphIns;
1015 glyph->control_len = n_ins;
1016
David Turner8f43c712000-02-02 12:16:19 +00001017 error = TT_Set_CodeRange( exec,
1018 tt_coderange_glyph,
1019 exec->glyphIns,
1020 n_ins );
Werner Lemberg78575dc2000-06-12 19:36:41 +00001021 if ( error )
1022 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00001023
David Turner8f43c712000-02-02 12:16:19 +00001024 /* prepare the execution context */
Werner Lemberga929ba92000-06-25 06:47:11 +00001025 tt_prepare_zone( &exec->pts, &gloader->base,
1026 start_point, start_contour );
David Turnerf0df85b2000-06-22 00:17:42 +00001027 pts = &exec->pts;
David Turnere49ab252000-05-16 23:44:38 +00001028
David Turner8f43c712000-02-02 12:16:19 +00001029 pts->n_points = num_points + 2;
David Turner43a2f652000-07-05 18:23:38 +00001030 pts->n_contours = gloader->base.outline.n_contours;
David Turnere49ab252000-05-16 23:44:38 +00001031
David Turner8f43c712000-02-02 12:16:19 +00001032 /* add phantom points */
1033 pp1 = pts->cur + num_points;
1034 pp1[0] = loader->pp1;
1035 pp1[1] = loader->pp2;
David Turnere49ab252000-05-16 23:44:38 +00001036
Werner Lembergdeb4e982000-06-29 03:14:25 +00001037 pts->tags[num_points ] = 0;
David Turner41dbcbf2000-03-09 11:46:25 +00001038 pts->tags[num_points + 1] = 0;
David Turnere49ab252000-05-16 23:44:38 +00001039
David Turner8f43c712000-02-02 12:16:19 +00001040 /* if hinting, round the phantom points */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001041 if ( IS_HINTED( loader->load_flags ) )
David Turner8f43c712000-02-02 12:16:19 +00001042 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001043 pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 );
1044 pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 );
David Turner8f43c712000-02-02 12:16:19 +00001045 }
David Turnere49ab252000-05-16 23:44:38 +00001046
David Turner8f43c712000-02-02 12:16:19 +00001047 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001048 FT_UInt k;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001049
1050
David Turner43a2f652000-07-05 18:23:38 +00001051 for ( k = 0; k < num_points; k++ )
David Turner41dbcbf2000-03-09 11:46:25 +00001052 pts->tags[k] &= FT_Curve_Tag_On;
David Turner8f43c712000-02-02 12:16:19 +00001053 }
David Turnere49ab252000-05-16 23:44:38 +00001054
Werner Lemberg7fa51b52000-07-08 19:51:42 +00001055 cur_to_org( num_points + 2, pts );
David Turnere49ab252000-05-16 23:44:38 +00001056
David Turner8f43c712000-02-02 12:16:19 +00001057 /* now consider hinting */
Werner Lembergdcd2e142000-06-25 07:43:15 +00001058 if ( IS_HINTED( loader->load_flags ) && n_ins > 0 )
David Turner8f43c712000-02-02 12:16:19 +00001059 {
1060 exec->is_composite = TRUE;
1061 exec->pedantic_hinting =
Werner Lembergdcd2e142000-06-25 07:43:15 +00001062 (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC );
David Turnere49ab252000-05-16 23:44:38 +00001063
David Turnerc3128612000-06-23 05:02:13 +00001064 error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug );
David Turner8f43c712000-02-02 12:16:19 +00001065 if ( error && exec->pedantic_hinting )
1066 goto Fail;
1067 }
David Turnere49ab252000-05-16 23:44:38 +00001068
David Turner8f43c712000-02-02 12:16:19 +00001069 /* save glyph origin and advance points */
1070 loader->pp1 = pp1[0];
1071 loader->pp2 = pp1[1];
1072 }
Werner Lembergdcd2e142000-06-25 07:43:15 +00001073
Werner Lemberg78575dc2000-06-12 19:36:41 +00001074#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
Werner Lembergdcd2e142000-06-25 07:43:15 +00001075
David Turnerd2b1f351999-12-16 23:11:37 +00001076 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001077 /* end of composite loading */
David Turnerd2b1f351999-12-16 23:11:37 +00001078 }
1079
Werner Lemberg78575dc2000-06-12 19:36:41 +00001080 /***********************************************************************/
1081 /***********************************************************************/
1082 /***********************************************************************/
David Turnerd2b1f351999-12-16 23:11:37 +00001083
David Turner8f43c712000-02-02 12:16:19 +00001084 Fail:
Werner Lemberga929ba92000-06-25 06:47:11 +00001085 if ( opened_frame )
David Turner994d7742000-06-25 04:49:19 +00001086 face->forget_glyph_frame( loader );
David Turner90f68b72000-06-23 12:26:14 +00001087
1088 Exit:
David Turnere49ab252000-05-16 23:44:38 +00001089 return error;
David Turner8f43c712000-02-02 12:16:19 +00001090 }
1091
1092
David Turner8f43c712000-02-02 12:16:19 +00001093 static
Werner Lemberg78575dc2000-06-12 19:36:41 +00001094 void compute_glyph_metrics( TT_Loader* loader,
David Turnerf9b8dec2000-06-16 19:34:52 +00001095 FT_UInt glyph_index )
David Turner8f43c712000-02-02 12:16:19 +00001096 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001097 FT_BBox bbox;
David Turnerc3128612000-06-23 05:02:13 +00001098 TT_Face face = (TT_Face)loader->face;
David Turnerf9b8dec2000-06-16 19:34:52 +00001099 FT_Fixed x_scale, y_scale;
David Turner8f43c712000-02-02 12:16:19 +00001100 TT_GlyphSlot glyph = loader->glyph;
David Turnerc3128612000-06-23 05:02:13 +00001101 TT_Size size = (TT_Size)loader->size;
David Turnere49ab252000-05-16 23:44:38 +00001102
Werner Lembergdcd2e142000-06-25 07:43:15 +00001103
Werner Lemberg78575dc2000-06-12 19:36:41 +00001104 x_scale = 0x10000L;
1105 y_scale = 0x10000L;
1106 if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
David Turner8f43c712000-02-02 12:16:19 +00001107 {
1108 x_scale = size->root.metrics.x_scale;
1109 y_scale = size->root.metrics.y_scale;
1110 }
David Turnere49ab252000-05-16 23:44:38 +00001111
David Turnered7f62a2000-03-28 11:19:28 +00001112 if ( glyph->format != ft_glyph_format_composite )
David Turner8f43c712000-02-02 12:16:19 +00001113 {
David Turnerf0df85b2000-06-22 00:17:42 +00001114 glyph->outline.flags &= ~ft_outline_single_pass;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001115
David Turnerf0df85b2000-06-22 00:17:42 +00001116 /* copy outline to our glyph slot */
1117 FT_GlyphLoader_Copy_Points( glyph->loader, loader->gloader );
1118 glyph->outline = glyph->loader->base.outline;
Werner Lembergbd5ae402000-07-05 04:32:02 +00001119
David Turnered7f62a2000-03-28 11:19:28 +00001120 /* translate array so that (0,0) is the glyph's origin */
David Turnerf0df85b2000-06-22 00:17:42 +00001121 FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 );
David Turnere49ab252000-05-16 23:44:38 +00001122
David Turnered7f62a2000-03-28 11:19:28 +00001123 FT_Outline_Get_CBox( &glyph->outline, &bbox );
1124
Werner Lemberg78575dc2000-06-12 19:36:41 +00001125 if ( IS_HINTED( loader->load_flags ) )
David Turnered7f62a2000-03-28 11:19:28 +00001126 {
1127 /* grid-fit the bounding box */
1128 bbox.xMin &= -64;
1129 bbox.yMin &= -64;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001130 bbox.xMax = ( bbox.xMax + 63 ) & -64;
1131 bbox.yMax = ( bbox.yMax + 63 ) & -64;
David Turnered7f62a2000-03-28 11:19:28 +00001132 }
David Turner8f43c712000-02-02 12:16:19 +00001133 }
David Turnered7f62a2000-03-28 11:19:28 +00001134 else
1135 bbox = loader->bbox;
David Turnerd2b1f351999-12-16 23:11:37 +00001136
Werner Lemberga929ba92000-06-25 06:47:11 +00001137 /* get the device-independent horizontal advance. It is scaled later */
1138 /* by the base layer. */
David Turnerd2b1f351999-12-16 23:11:37 +00001139 {
David Turnerf0df85b2000-06-22 00:17:42 +00001140 FT_Pos advance = loader->advance;
David Turnerd2b1f351999-12-16 23:11:37 +00001141
Werner Lemberga929ba92000-06-25 06:47:11 +00001142
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001143 /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */
1144 /* correctly support DynaLab fonts, which have an incorrect */
1145 /* `advance_Width_Max' field! It is used, to my knowledge, */
1146 /* exclusively in the X-TrueType font server. */
1147 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001148 if ( face->postscript.isFixedPitch &&
1149 ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00001150 advance = face->horizontal.advance_Width_Max;
1151
David Turnerf0df85b2000-06-22 00:17:42 +00001152 /* we need to return the advance in font units in linearHoriAdvance, */
Werner Lemberga929ba92000-06-25 06:47:11 +00001153 /* it will be scaled later by the base layer. */
David Turnerf0df85b2000-06-22 00:17:42 +00001154 glyph->linearHoriAdvance = advance;
David Turnerd2b1f351999-12-16 23:11:37 +00001155 }
1156
1157 glyph->metrics.horiBearingX = bbox.xMin;
1158 glyph->metrics.horiBearingY = bbox.yMax;
David Turner8f43c712000-02-02 12:16:19 +00001159 glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
David Turnerd2b1f351999-12-16 23:11:37 +00001160
1161 /* Now take care of vertical metrics. In the case where there is */
1162 /* no vertical information within the font (relatively common), make */
1163 /* up some metrics by `hand'... */
1164
1165 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001166 FT_Short top_bearing; /* vertical top side bearing (EM units) */
1167 FT_UShort advance_height; /* vertical advance height (EM units) */
David Turnerd2b1f351999-12-16 23:11:37 +00001168
David Turnerf9b8dec2000-06-16 19:34:52 +00001169 FT_Pos left; /* scaled vertical left side bearing */
1170 FT_Pos Top; /* scaled original vertical top side bearing */
1171 FT_Pos top; /* scaled vertical top side bearing */
1172 FT_Pos advance; /* scaled vertical advance height */
David Turnerd2b1f351999-12-16 23:11:37 +00001173
1174
1175 /* Get the unscaled `tsb' and `ah' */
1176 if ( face->vertical_info &&
1177 face->vertical.number_Of_VMetrics > 0 )
1178 {
1179 /* Don't assume that both the vertical header and vertical */
1180 /* metrics are present in the same font :-) */
1181
1182 TT_Get_Metrics( (TT_HoriHeader*)&face->vertical,
1183 glyph_index,
1184 &top_bearing,
1185 &advance_height );
1186 }
1187 else
1188 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001189 /* Make up the distances from the horizontal header. */
David Turnerd2b1f351999-12-16 23:11:37 +00001190
Werner Lemberg78575dc2000-06-12 19:36:41 +00001191 /* NOTE: The OS/2 values are the only `portable' ones, */
1192 /* which is why we use them, if there is an OS/2 */
1193 /* table in the font. Otherwise, we use the */
1194 /* values defined in the horizontal header. */
1195 /* */
1196 /* NOTE2: The sTypoDescender is negative, which is why */
1197 /* we compute the baseline-to-baseline distance */
1198 /* here with: */
1199 /* ascender - descender + linegap */
1200 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001201 if ( face->os2.version != 0xFFFF )
1202 {
1203 top_bearing = face->os2.sTypoLineGap / 2;
David Turnerf9b8dec2000-06-16 19:34:52 +00001204 advance_height = (FT_UShort)( face->os2.sTypoAscender -
Werner Lemberg78575dc2000-06-12 19:36:41 +00001205 face->os2.sTypoDescender +
1206 face->os2.sTypoLineGap );
David Turnerd2b1f351999-12-16 23:11:37 +00001207 }
1208 else
1209 {
1210 top_bearing = face->horizontal.Line_Gap / 2;
David Turnerf9b8dec2000-06-16 19:34:52 +00001211 advance_height = (FT_UShort)( face->horizontal.Ascender +
Werner Lemberg78575dc2000-06-12 19:36:41 +00001212 face->horizontal.Descender +
1213 face->horizontal.Line_Gap );
David Turnerd2b1f351999-12-16 23:11:37 +00001214 }
1215 }
1216
Werner Lemberg78575dc2000-06-12 19:36:41 +00001217 /* We must adjust the top_bearing value from the bounding box given */
1218 /* in the glyph header to te bounding box calculated with */
David Turnerf0df85b2000-06-22 00:17:42 +00001219 /* FT_Get_Outline_CBox(). */
David Turnerfc1f9892000-01-07 18:44:50 +00001220
David Turnerd2b1f351999-12-16 23:11:37 +00001221 /* scale the metrics */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001222 if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001223 {
David Turner8f43c712000-02-02 12:16:19 +00001224 Top = FT_MulFix( top_bearing, y_scale );
1225 top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
1226 - bbox.yMax;
1227 advance = FT_MulFix( advance_height, y_scale );
David Turnerd2b1f351999-12-16 23:11:37 +00001228 }
1229 else
1230 {
David Turnerfc1f9892000-01-07 18:44:50 +00001231 Top = top_bearing;
David Turner8f43c712000-02-02 12:16:19 +00001232 top = top_bearing + loader->bbox.yMax - bbox.yMax;
David Turnerd2b1f351999-12-16 23:11:37 +00001233 advance = advance_height;
1234 }
1235
Werner Lemberga929ba92000-06-25 06:47:11 +00001236 /* set the advance height in design units. It is scaled later by */
1237 /* the base layer. */
David Turnerf0df85b2000-06-22 00:17:42 +00001238 glyph->linearVertAdvance = advance_height;
David Turnerd2b1f351999-12-16 23:11:37 +00001239
Werner Lemberga929ba92000-06-25 06:47:11 +00001240 /* XXX: for now, we have no better algorithm for the lsb, but it */
1241 /* should work fine. */
1242 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001243 left = ( bbox.xMin - bbox.xMax ) / 2;
1244
1245 /* grid-fit them if necessary */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001246 if ( IS_HINTED( loader->load_flags ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001247 {
1248 left &= -64;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001249 top = ( top + 63 ) & -64;
1250 advance = ( advance + 32 ) & -64;
David Turnerd2b1f351999-12-16 23:11:37 +00001251 }
1252
1253 glyph->metrics.vertBearingX = left;
1254 glyph->metrics.vertBearingY = top;
1255 glyph->metrics.vertAdvance = advance;
1256 }
1257
Werner Lembergdcd2e142000-06-25 07:43:15 +00001258 /* adjust advance width to the value contained in the hdmx table */
David Turner8f43c712000-02-02 12:16:19 +00001259 if ( !face->postscript.isFixedPitch && size &&
Werner Lemberg78575dc2000-06-12 19:36:41 +00001260 IS_HINTED( loader->load_flags ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001261 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001262 FT_Byte* widths = Get_Advance_Widths( face,
Werner Lemberg78575dc2000-06-12 19:36:41 +00001263 size->root.metrics.x_ppem );
Werner Lembergdcd2e142000-06-25 07:43:15 +00001264
1265
David Turnerd2b1f351999-12-16 23:11:37 +00001266 if ( widths )
1267 glyph->metrics.horiAdvance = widths[glyph_index] << 6;
1268 }
1269
David Turnerd2b1f351999-12-16 23:11:37 +00001270 /* set glyph dimensions */
1271 glyph->metrics.width = bbox.xMax - bbox.xMin;
1272 glyph->metrics.height = bbox.yMax - bbox.yMin;
David Turner8f43c712000-02-02 12:16:19 +00001273 }
David Turnerd2b1f351999-12-16 23:11:37 +00001274
David Turnerd2b1f351999-12-16 23:11:37 +00001275
Werner Lemberg78575dc2000-06-12 19:36:41 +00001276 /*************************************************************************/
1277 /* */
1278 /* <Function> */
1279 /* TT_Load_Glyph */
1280 /* */
1281 /* <Description> */
1282 /* A function used to load a single glyph within a given glyph slot, */
1283 /* for a given size. */
1284 /* */
1285 /* <Input> */
1286 /* glyph :: A handle to a target slot object where the glyph */
1287 /* will be loaded. */
1288 /* */
1289 /* size :: A handle to the source face size at which the glyph */
1290 /* must be scaled/loaded. */
1291 /* */
1292 /* glyph_index :: The index of the glyph in the font file. */
1293 /* */
1294 /* load_flags :: A flag indicating what to load for this glyph. The */
1295 /* FT_LOAD_XXX constants can be used to control the */
1296 /* glyph loading process (e.g., whether the outline */
1297 /* should be scaled, whether to load bitmaps or not, */
1298 /* whether to hint the outline, etc). */
1299 /* */
1300 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +00001301 /* FreeType error code. 0 means success. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001302 /* */
David Turner8f43c712000-02-02 12:16:19 +00001303 LOCAL_FUNC
David Turnerf9b8dec2000-06-16 19:34:52 +00001304 FT_Error TT_Load_Glyph( TT_Size size,
David Turner8f43c712000-02-02 12:16:19 +00001305 TT_GlyphSlot glyph,
David Turnerf9b8dec2000-06-16 19:34:52 +00001306 FT_UShort glyph_index,
1307 FT_UInt load_flags )
David Turner8f43c712000-02-02 12:16:19 +00001308 {
1309 SFNT_Interface* sfnt;
1310 TT_Face face;
1311 FT_Stream stream;
1312 FT_Memory memory;
David Turnerf9b8dec2000-06-16 19:34:52 +00001313 FT_Error error;
David Turner8f43c712000-02-02 12:16:19 +00001314 TT_Loader loader;
David Turnere49ab252000-05-16 23:44:38 +00001315
Werner Lemberg78575dc2000-06-12 19:36:41 +00001316
David Turner8f43c712000-02-02 12:16:19 +00001317 face = (TT_Face)glyph->face;
1318 sfnt = (SFNT_Interface*)face->sfnt;
1319 stream = face->root.stream;
1320 memory = face->root.memory;
1321 error = 0;
David Turnered7f62a2000-03-28 11:19:28 +00001322
Werner Lemberg78575dc2000-06-12 19:36:41 +00001323 if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) ||
1324 ( load_flags & FT_LOAD_NO_RECURSE ) )
David Turner8f43c712000-02-02 12:16:19 +00001325 {
1326 size = NULL;
1327 load_flags |= FT_LOAD_NO_SCALE |
1328 FT_LOAD_NO_HINTING |
1329 FT_LOAD_NO_BITMAP;
1330 }
1331
David Turnered7f62a2000-03-28 11:19:28 +00001332 glyph->num_subglyphs = 0;
1333
David Turner8f43c712000-02-02 12:16:19 +00001334#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
Werner Lemberg78575dc2000-06-12 19:36:41 +00001335
1336 /* try to load embedded bitmap if any */
1337 if ( size &&
1338 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 &&
1339 sfnt->load_sbits )
David Turner8f43c712000-02-02 12:16:19 +00001340 {
1341 TT_SBit_Metrics metrics;
David Turnere49ab252000-05-16 23:44:38 +00001342
Werner Lemberg78575dc2000-06-12 19:36:41 +00001343
David Turner8f43c712000-02-02 12:16:19 +00001344 error = sfnt->load_sbit_image( face,
1345 size->root.metrics.x_ppem,
1346 size->root.metrics.y_ppem,
1347 glyph_index,
David Turner109fcf62000-05-17 23:35:37 +00001348 load_flags,
David Turner8f43c712000-02-02 12:16:19 +00001349 stream,
1350 &glyph->bitmap,
1351 &metrics );
1352 if ( !error )
1353 {
1354 glyph->outline.n_points = 0;
1355 glyph->outline.n_contours = 0;
1356
David Turnerf9b8dec2000-06-16 19:34:52 +00001357 glyph->metrics.width = (FT_Pos)metrics.width << 6;
1358 glyph->metrics.height = (FT_Pos)metrics.height << 6;
David Turner8f43c712000-02-02 12:16:19 +00001359
David Turnerf9b8dec2000-06-16 19:34:52 +00001360 glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
1361 glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
1362 glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6;
David Turner8f43c712000-02-02 12:16:19 +00001363
David Turnerf9b8dec2000-06-16 19:34:52 +00001364 glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
1365 glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
1366 glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6;
David Turner8f43c712000-02-02 12:16:19 +00001367
1368 glyph->format = ft_glyph_format_bitmap;
David Turnerf0df85b2000-06-22 00:17:42 +00001369 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
1370 {
David Turnere161ee42000-07-10 22:03:10 +00001371 glyph->bitmap_left = metrics.vertBearingX;
1372 glyph->bitmap_top = metrics.vertBearingY;
David Turnerf0df85b2000-06-22 00:17:42 +00001373 }
1374 else
1375 {
David Turnere161ee42000-07-10 22:03:10 +00001376 glyph->bitmap_left = metrics.horiBearingX;
1377 glyph->bitmap_top = metrics.horiBearingY;
David Turnerf0df85b2000-06-22 00:17:42 +00001378 }
David Turner8f43c712000-02-02 12:16:19 +00001379 return error;
1380 }
1381 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001382
David Turner8f43c712000-02-02 12:16:19 +00001383#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
1384
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001385 /* seek to the beginning of the glyph table. For Type 42 fonts */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001386 /* the table might be accessed from a Postscript stream or something */
1387 /* else... */
1388
David Turner8f43c712000-02-02 12:16:19 +00001389 error = face->goto_table( face, TTAG_glyf, stream, 0 );
Werner Lemberg78575dc2000-06-12 19:36:41 +00001390 if ( error )
David Turner8f43c712000-02-02 12:16:19 +00001391 {
Werner Lembergdcd2e142000-06-25 07:43:15 +00001392 FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" ));
David Turner08fdac92000-02-21 16:01:33 +00001393 goto Exit;
David Turner8f43c712000-02-02 12:16:19 +00001394 }
1395
Werner Lemberg78575dc2000-06-12 19:36:41 +00001396 MEM_Set( &loader, 0, sizeof ( loader ) );
David Turner8f43c712000-02-02 12:16:19 +00001397
David Turner08fdac92000-02-21 16:01:33 +00001398 /* update the glyph zone bounds */
David Turner08fdac92000-02-21 16:01:33 +00001399 {
David Turnerf0df85b2000-06-22 00:17:42 +00001400 FT_GlyphLoader* gloader = FT_FACE_DRIVER(face)->glyph_loader;
Werner Lemberga929ba92000-06-25 06:47:11 +00001401
Werner Lembergbd5ae402000-07-05 04:32:02 +00001402
David Turnerf0df85b2000-06-22 00:17:42 +00001403 loader.gloader = gloader;
Werner Lembergbd5ae402000-07-05 04:32:02 +00001404
David Turnerf0df85b2000-06-22 00:17:42 +00001405 FT_GlyphLoader_Rewind( gloader );
Werner Lembergbd5ae402000-07-05 04:32:02 +00001406
David Turnerf0df85b2000-06-22 00:17:42 +00001407 tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 );
1408 tt_prepare_zone( &loader.base, &gloader->base, 0, 0 );
David Turner08fdac92000-02-21 16:01:33 +00001409 }
David Turner08fdac92000-02-21 16:01:33 +00001410
David Turner8f43c712000-02-02 12:16:19 +00001411#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberg78575dc2000-06-12 19:36:41 +00001412
David Turner8f43c712000-02-02 12:16:19 +00001413 if ( size )
1414 {
1415 /* query new execution context */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001416 loader.exec = size->debug ? size->context : TT_New_Context( face );
David Turner8f43c712000-02-02 12:16:19 +00001417 if ( !loader.exec )
1418 return TT_Err_Could_Not_Find_Context;
David Turnere49ab252000-05-16 23:44:38 +00001419
David Turner8f43c712000-02-02 12:16:19 +00001420 TT_Load_Context( loader.exec, face, size );
David Turnerc3128612000-06-23 05:02:13 +00001421 loader.instructions = loader.exec->glyphIns;
David Turner8f43c712000-02-02 12:16:19 +00001422
1423 /* load default graphics state - if needed */
1424 if ( size->GS.instruct_control & 2 )
1425 loader.exec->GS = tt_default_graphics_state;
1426 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001427
David Turner8f43c712000-02-02 12:16:19 +00001428#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
1429
Werner Lemberg78575dc2000-06-12 19:36:41 +00001430 /* clear all outline flags, except the `owner' one */
David Turner81bb4ad2000-06-28 04:19:49 +00001431 glyph->outline.flags = 0;
David Turnere49ab252000-05-16 23:44:38 +00001432
David Turner04aa8002000-06-01 03:27:48 +00001433 if ( size && size->root.metrics.y_ppem < 24 )
David Turner41dbcbf2000-03-09 11:46:25 +00001434 glyph->outline.flags |= ft_outline_high_precision;
David Turner8f43c712000-02-02 12:16:19 +00001435
Werner Lemberg78575dc2000-06-12 19:36:41 +00001436 /* let's initialize the rest of our loader now */
1437
David Turner8f43c712000-02-02 12:16:19 +00001438 loader.load_flags = load_flags;
1439
David Turnerc3128612000-06-23 05:02:13 +00001440 loader.face = (FT_Face)face;
1441 loader.size = (FT_Size)size;
1442 loader.glyph = (FT_GlyphSlot)glyph;
David Turner8f43c712000-02-02 12:16:19 +00001443 loader.stream = stream;
Werner Lembergbd5ae402000-07-05 04:32:02 +00001444
David Turnerc3128612000-06-23 05:02:13 +00001445 loader.glyf_offset = FILE_Pos();
David Turner8f43c712000-02-02 12:16:19 +00001446
1447#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lemberg78575dc2000-06-12 19:36:41 +00001448
1449 /* if the cvt program has disabled hinting, the argument */
1450 /* is ignored. */
1451 if ( size && ( size->GS.instruct_control & 1 ) )
David Turner8f43c712000-02-02 12:16:19 +00001452 loader.load_flags |= FT_LOAD_NO_HINTING;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001453
1454#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
David Turner8f43c712000-02-02 12:16:19 +00001455
1456 /* Main loading loop */
David Turner3475e7f2000-05-17 20:56:01 +00001457 glyph->format = ft_glyph_format_outline;
Werner Lemberg78575dc2000-06-12 19:36:41 +00001458 glyph->num_subglyphs = 0;
David Turner8f43c712000-02-02 12:16:19 +00001459 error = load_truetype_glyph( &loader, glyph_index );
Werner Lemberg78575dc2000-06-12 19:36:41 +00001460 if ( !error )
David Turner8f43c712000-02-02 12:16:19 +00001461 compute_glyph_metrics( &loader, glyph_index );
1462
1463#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Werner Lembergdcd2e142000-06-25 07:43:15 +00001464
David Turnerd2b1f351999-12-16 23:11:37 +00001465 if ( !size || !size->debug )
David Turner8f43c712000-02-02 12:16:19 +00001466 TT_Done_Context( loader.exec );
Werner Lembergdcd2e142000-06-25 07:43:15 +00001467
1468#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
David Turnerd2b1f351999-12-16 23:11:37 +00001469
David Turner08fdac92000-02-21 16:01:33 +00001470 Exit:
David Turnerd2b1f351999-12-16 23:11:37 +00001471 return error;
1472 }
1473
1474
David Turnerd2b1f351999-12-16 23:11:37 +00001475/* END */