]>
Commit | Line | Data |
---|---|---|
1 | #include <oltypes.h> | |
2 | ||
3 | LOCAL_FUNC | |
4 | TT_Error OTL_Table_Init( OTL_Table* table, | |
5 | FT_Memory memory ) | |
6 | { | |
7 | MEM_Set( table, 0, sizeof(*table) ); | |
8 | table->memory = memory; | |
9 | } | |
10 | ||
11 | /* read a script list table */ | |
12 | /* use with any table */ | |
13 | LOCAL_FUNC | |
14 | TT_Error OTL_Table_Set_Scripts( OTL_Table* table, | |
15 | TT_Byte* bytes, | |
16 | TT_Long len, | |
17 | OTL_Type otl_type ) | |
18 | { | |
19 | TT_Byte* p; | |
20 | TT_Byte* start = bytes; | |
21 | TT_UInt count, max_langs; | |
22 | TT_Error error; | |
23 | ||
24 | /* skip version of the JSTF table */ | |
25 | if (otl_type == otl_jstf) | |
26 | start += 4; | |
27 | ||
28 | p = start; | |
29 | ||
30 | /* we must allocate the script_tags and language_tags arrays */ | |
31 | /* this requires that we compute the maximum number of languages */ | |
32 | /* per script.. */ | |
33 | ||
34 | count = table->num_scripts = OTL_UShort(p); | |
35 | max_langs = 0; | |
36 | for ( ; count > 0; count++ ) | |
37 | { | |
38 | TT_Byte* script; | |
39 | TT_UInt num_langs; | |
40 | ||
41 | p += 4; /* skip tag */ | |
42 | script = bytes + OTL_UShort(p); | |
43 | ||
44 | /* skip the baseValues or extenders field of the BASE and JSTF table */ | |
45 | if (otl_type == otl_type_base || otl_type == otl_type_jstf) | |
46 | script += 2; | |
47 | ||
48 | /* test if there is a default language system */ | |
49 | if ( OTL_UShort(script) ) | |
50 | num_langs++; | |
51 | ||
52 | /* test other language systems */ | |
53 | num_langs += OTL_UShort(script); /* add other lang sys */ | |
54 | ||
55 | if (num_langs > max_langs) | |
56 | max_langs = num_langs; | |
57 | } | |
58 | ||
59 | /* good, now allocate the tag arrays */ | |
60 | if ( !ALLOC_ARRAY( table->script_tags, | |
61 | table->num_scripts + max_langs, | |
62 | TT_ULong ) ) | |
63 | { | |
64 | table->language_tags = table->script_tags + table->num_scripts; | |
65 | table->max_languages = max_langs; | |
66 | table->num_languages = 0; | |
67 | table->otl_type = otl_type; | |
68 | ||
69 | table->scripts_table = bytes; | |
70 | table->scripts_len = len; | |
71 | ||
72 | /* fill the script_tags array */ | |
73 | { | |
74 | TT_UInt n; | |
75 | TT_Byte* p = start + 2; /* skip count */ | |
76 | ||
77 | for ( n = 0; n < table->num_scripts; n++ ) | |
78 | { | |
79 | table->script_tags[n] = OTL_ULong(p); | |
80 | p += 2; /* skip offset */ | |
81 | } | |
82 | } | |
83 | } | |
84 | return error; | |
85 | } | |
86 | ||
87 | ||
88 | ||
89 | /* add a features list to the table */ | |
90 | /* use only with a GSUB or GPOS table */ | |
91 | LOCAL_FUNC | |
92 | TT_Error OTL_Table_Set_Features( OTL_Table* table, | |
93 | TT_Byte* bytes, | |
94 | TT_Long len ) | |
95 | { | |
96 | TT_Error error; | |
97 | TT_Byte* p = bytes; | |
98 | TT_UInt count; | |
99 | ||
100 | table->max_features = count = OTL_UShort(p); | |
101 | if ( !ALLOC_ARRAY( table->feature_tags, count, TT_ULong ) && | |
102 | !ALLOC_ARRAY( table->features, count, TT_Bool ) ) | |
103 | { | |
104 | table->features_table = bytes; | |
105 | table->features_len = len; | |
106 | } | |
107 | return error; | |
108 | } | |
109 | ||
110 | ||
111 | /* add a lookup list to the table */ | |
112 | /* use only with a GSUB or GPOS table */ | |
113 | LOCAL_FUNC | |
114 | TT_Error OTL_Table_Set_Lookups( OTL_Table* table, | |
115 | TT_Byte* bytes, | |
116 | TT_Long len ) | |
117 | { | |
118 | TT_Error error; | |
119 | TT_Byte* p = bytes; | |
120 | TT_UInt count; | |
121 | ||
122 | table->max_lookups = count = OTL_UShort(p); | |
123 | if ( !ALLOC_ARRAY( table->lookups, count, TT_Bool ) ) | |
124 | { | |
125 | table->lookups_table = bytes; | |
126 | table->lookups_len = len; | |
127 | } | |
128 | return error; | |
129 | } | |
130 | ||
131 | /* discard table arrays */ | |
132 | LOCAL_FUNC | |
133 | void OTL_Table_Done( OTL_Table* table ) | |
134 | { | |
135 | FREE( table->scrip_tags ); | |
136 | FREE( table->language_tags ); | |
137 | FREE( table->feature_tags ); | |
138 | FREE( table->lookups ); | |
139 | } | |
140 | ||
141 | ||
142 | /* return the list of available languages for a given script */ | |
143 | /* use with any table.. */ | |
144 | LOCAL_FUNC | |
145 | void OTL_Get_Languages_List( OTL_Table* table, | |
146 | TT_ULong script_tag ) | |
147 | { | |
148 | TT_UInt n; | |
149 | TT_Byte* p; | |
150 | TT_Byte* script = 0; | |
151 | TT_Byte* start = table->scripts_table; | |
152 | ||
153 | if ( table->otl_type == otl_type_jstf ) /* skip version for JSTF */ | |
154 | start += 4; | |
155 | ||
156 | p = start + 6; /* skip count+first tag */ | |
157 | ||
158 | for ( n = 0; n < table->num_scripts; n++, p += 6 ) | |
159 | { | |
160 | if ( table->script_tags[n] == script_tag ) | |
161 | { | |
162 | script = table->scripts_table + OTL_UShort(p); | |
163 | break; | |
164 | } | |
165 | } | |
166 | ||
167 | table->cur_script = script; | |
168 | if (!script) | |
169 | table->num_languages = 0; | |
170 | else | |
171 | { | |
172 | /* now fill the language_tags array with the appropriate values */ | |
173 | /* not that we put a '0' tag in front of the list to indicate that */ | |
174 | /* there is a default language for this script.. */ | |
175 | TT_ULong* tags = table->language_tags; | |
176 | ||
177 | switch (table->otl_type) | |
178 | { | |
179 | case otl_type_base: | |
180 | case otl_type_jstf: | |
181 | script += 2; /* skip basevalue or extenders */ | |
182 | /* fall-through */ | |
183 | ||
184 | default: | |
185 | if ( OTL_UShort(script) ) | |
186 | *tags++ = 0; | |
187 | } | |
188 | ||
189 | count = OTL_UShort(script); | |
190 | for ( ; count > 0; count-- ) | |
191 | { | |
192 | *tags++ = OTL_ULong(script); | |
193 | script += 2; /* skip offset */ | |
194 | } | |
195 | ||
196 | table->num_langs = tags - table->language_tags; | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | /* return the list of available features for the current script/language */ | |
202 | /* use with a GPOS or GSUB script table */ | |
203 | LOCAL_FUNC | |
204 | void OTL_Get_Features_List( OTL_Table* table, | |
205 | TT_ULong language_tag ) | |
206 | { | |
207 | TT_UInt n; | |
208 | TT_Byte* script = table->cur_script; | |
209 | TT_Byte* language = 0; | |
210 | TT_UShort offset; | |
211 | ||
212 | /* clear feature selection table */ | |
213 | for ( n = 0; n < table->max_features; n++ ) | |
214 | table->features[n] = 0; | |
215 | ||
216 | /* now, look for the current language */ | |
217 | if ( language_tag == 0 ) | |
218 | { | |
219 | offset = OTL_UShort(script); | |
220 | if (!offset) return; /* if there is no default language, exit */ | |
221 | ||
222 | language = script - 2 + offset; | |
223 | } | |
224 | else | |
225 | { | |
226 | TT_Byte* p = script + 8; /* skip default+count+1st tag */ | |
227 | TT_UShort index; | |
228 | ||
229 | for ( n = 0; n < table->num_languages; n++, p+=6 ) | |
230 | { | |
231 | if ( table->language_tags[n] == language_tag ) | |
232 | { | |
233 | language = script + OTL_UShort(p); | |
234 | break; | |
235 | } | |
236 | } | |
237 | ||
238 | table->cur_language = language; | |
239 | if (!language) return; | |
240 | ||
241 | p = language + 2; /* skip lookup order */ | |
242 | index = OTL_UShort(p); /* required feature index */ | |
243 | if (index != 0xFFFF) | |
244 | { | |
245 | if (index < table->max_features) | |
246 | table->features[index] = 1; | |
247 | } | |
248 | ||
249 | count = OTL_UShort(p); | |
250 | for ( ; count > 0; count-- ) | |
251 | { | |
252 | index = OTL_UShort(p); | |
253 | if (index < table->max_features) | |
254 | table->features[index] = 1; | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | ||
260 | /* return the list of lookups for the current features list */ | |
261 | /* use only with a GSUB or GPOS table */ | |
262 | LOCAL_FUNC | |
263 | void OTL_Get_Lookups_List( OTL_Table* table ) | |
264 | { | |
265 | TT_UInt n; | |
266 | TT_Byte* features = table->features_table; | |
267 | TT_Byte* p = features + 6; /* skip count+1st tag */ | |
268 | ||
269 | /* clear lookup list */ | |
270 | for ( n = 0; n < table->max_lookups; n++ ) | |
271 | table->lookups[n] = 0; | |
272 | ||
273 | /* now, parse the features list */ | |
274 | for ( n = 0; n < table->features; n++ ) | |
275 | { | |
276 | if (table->features[n]) | |
277 | { | |
278 | TT_UInt count; | |
279 | TT_UShort index; | |
280 | TT_Byte* feature; | |
281 | ||
282 | feature = features + OTL_UShort(p); | |
283 | p += 4; /* skip tag */ | |
284 | ||
285 | /* now, select all lookups from this feature */ | |
286 | count = OTL_UShort(feature); | |
287 | for ( ; count > 0; count-- ) | |
288 | { | |
289 | index = OTL_UShort(feature); | |
290 | if (index < table->max_lookups) | |
291 | table->lookups[index] = 1; | |
292 | } | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
297 | ||
298 | /* find the basevalues and minmax for the current script/language */ | |
299 | /* only use it with a BASE table.. */ | |
300 | LOCAL_FUNC | |
301 | void OTL_Get_Baseline_Values( OTL_Table* table, | |
302 | TT_ULong language_tag ) | |
303 | { | |
304 | TT_Byte* script = table->cur_script; | |
305 | TT_Byte* p = script; | |
306 | TT_UShort offset, count; | |
307 | ||
308 | table->cur_basevalues = 0; | |
309 | table->cur_minmax = 0; | |
310 | ||
311 | /* read basevalues */ | |
312 | offset = OTL_UShort(p); | |
313 | if (offset) | |
314 | table->cur_basevalues = script + offset; | |
315 | ||
316 | offset = OTL_UShort(p); | |
317 | if (offset) | |
318 | table->cur_minmax = script + offset; | |
319 | ||
320 | count = OTL_UShort(p); | |
321 | for ( ; count > 0; count-- ) | |
322 | { | |
323 | TT_ULong tag; | |
324 | ||
325 | tag = OTL_ULong(p); | |
326 | if ( language_tag == tag ) | |
327 | { | |
328 | table->cur_minmax = script + OTL_UShort(p); | |
329 | break; | |
330 | } | |
331 | p += 2; /* skip offset */ | |
332 | } | |
333 | } | |
334 | ||
335 | ||
336 | /* compute the coverage value of a given glyph id */ | |
337 | LOCAL_FUNC | |
338 | TT_Long OTL_Get_Coverage_Index( TT_Byte* coverage, | |
339 | TT_UInt glyph_id ) | |
340 | { | |
341 | TT_Long result = -1; | |
342 | TT_UInt count, index, start, end; | |
343 | TT_Byte* p = coverage; | |
344 | ||
345 | switch ( OTL_UShort(p) ) | |
346 | { | |
347 | case 1: /* coverage format 1 - array of glyph indices */ | |
348 | { | |
349 | count = OTL_UShort(p); | |
350 | for ( index = 0; index < count; index++ ) | |
351 | { | |
352 | if ( OTL_UShort(p) == glyph_id ) | |
353 | { | |
354 | result = index; | |
355 | break; | |
356 | } | |
357 | } | |
358 | } | |
359 | break; | |
360 | ||
361 | case 2: | |
362 | { | |
363 | count = OTL_UShort(p); | |
364 | for ( ; count > 0; count-- ) | |
365 | { | |
366 | start = OTL_UShort(p); | |
367 | end = OTL_UShort(p); | |
368 | index = OTL_UShort(p); | |
369 | if (start <= glyph_id && glyph_id <= end) | |
370 | { | |
371 | result = glyph_id - start + index; | |
372 | break; | |
373 | } | |
374 | } | |
375 | } | |
376 | break; | |
377 | } | |
378 | return result; | |
379 | } | |
380 | ||
381 | ||
382 | /* compute the class value of a given glyph_id */ | |
383 | LOCAL_FUNC | |
384 | TT_UInt OTL_Get_Glyph_Class( TT_Byte* class_def, | |
385 | TT_UInt glyph_id ) | |
386 | { | |
387 | TT_Byte* p = class_def; | |
388 | TT_UInt result = 0; | |
389 | TT_UInt start, end, count, index; | |
390 | ||
391 | switch ( OTL_UShort(p) ) | |
392 | { | |
393 | case 1: | |
394 | { | |
395 | start = OTL_UShort(p); | |
396 | count = OTL_UShort(p); | |
397 | ||
398 | glyph_id -= start; | |
399 | if (glyph_id < count) | |
400 | { | |
401 | p += 2*glyph_id; | |
402 | result = OTL_UShort(p); | |
403 | } | |
404 | } | |
405 | break; | |
406 | ||
407 | case 2: | |
408 | { | |
409 | count = OTL_UShort(p); | |
410 | for ( ; count > 0; count-- ) | |
411 | { | |
412 | start = OTL_UShort(p); | |
413 | end = OTL_UShort(p); | |
414 | index = OTL_UShort(p); | |
415 | if ( start <= glyph_id && glyph_id <= end ) | |
416 | { | |
417 | result = index; | |
418 | break; | |
419 | } | |
420 | } | |
421 | } | |
422 | break; | |
423 | } | |
424 | return result; | |
425 | } | |
426 | ||
427 | ||
428 | /* compute the adjustement necessary for a given device size */ | |
429 | LOCAL_FUNC | |
430 | TT_Int OTL_Get_Device_Adjustment( TT_Byte* device, | |
431 | TT_UInt size ) | |
432 | { | |
433 | TT_Byte* p = device; | |
434 | TT_Int result = 0; | |
435 | TT_UInt start, end; | |
436 | TT_Short value; | |
437 | ||
438 | start = OTL_UShort(p); | |
439 | end = OTL_UShort(p); | |
440 | if (size >= start && size <= end) | |
441 | { | |
442 | /* I know we could do all of this without a switch, with */ | |
443 | /* clever shifts and everything, but it makes the code */ | |
444 | /* really difficult to understand.. */ | |
445 | ||
446 | size -= start; | |
447 | switch ( OTL_UShort(p) ) | |
448 | { | |
449 | case 1: /* 2-bits per value */ | |
450 | { | |
451 | p += 2*(size >> 3); | |
452 | size = (size & 7) << 1; | |
453 | value = (TT_Short)((TT_Short)OTL_UShort(p) << size); | |
454 | result = value >> 14; | |
455 | } | |
456 | break; | |
457 | ||
458 | case 2: /* 4-bits per value */ | |
459 | { | |
460 | p += 2*(size >> 2); | |
461 | size = (size & 3) << 2; | |
462 | value = (TT_Short)((TT_Short)OTL_UShort(p) << size); | |
463 | result = value >> 12; | |
464 | } | |
465 | break; | |
466 | ||
467 | case 3: /* 8-bits per value */ | |
468 | { | |
469 | p += 2*(size >> 1); | |
470 | size = (size & 1) << 3; | |
471 | value = (TT_Short)((TT_Short)OTL_UShort(p) << size); | |
472 | result = value >> 8; | |
473 | } | |
474 | break; | |
475 | } | |
476 | } | |
477 | return result; | |
478 | } | |
479 | ||
480 | /* extract a BaseCoord value */ | |
481 | LOCAL_FUNC | |
482 | void OTL_Get_Base_Coordinate( TT_Byte* base_coord, | |
483 | OTL_ValueRecord* coord ) | |
484 | { | |
485 | TT_Byte* p = base_coord; | |
486 | TT_Int result = 0; | |
487 | ||
488 | coord->format = OTL_UShort(p); | |
489 | coord->coordinate = OTL_Short(p); | |
490 | coord->device = 0; | |
491 | ||
492 | switch (coord->format) | |
493 | { | |
494 | case 2: /* format 2 */ | |
495 | coord->ref_glyph = OTL_UShort(p); | |
496 | coord->ref_point = OTL_UShort(p); | |
497 | break; | |
498 | ||
499 | case 3: /* format 3 */ | |
500 | coord->device = p - 4 + OTL_UShort(p); | |
501 | break; | |
502 | ||
503 | default: | |
504 | ; | |
505 | } | |
506 | } | |
507 | ||
508 | ||
509 | /* compute size of ValueRecord */ | |
510 | LOCAL_FUNC | |
511 | TT_Int OTL_ValueRecord_Size( TT_UShort format ) | |
512 | { | |
513 | TT_Int count; | |
514 | ||
515 | /* each bit in the value format corresponds to a single ushort */ | |
516 | /* we thus count the bits, and multiply the result by 2 */ | |
517 | ||
518 | count = (TT_Int)(format & 0xFF); | |
519 | count = ((count & 0xAA) >> 1) + (count & 0x55); | |
520 | count = ((count & 0xCC) >> 2) + (count & 0x33); | |
521 | count = ((count & 0xF0) >> 4) + (count & 0x0F); | |
522 | ||
523 | return count*2; | |
524 | } | |
525 | ||
526 | ||
527 | ||
528 | /* extract ValueRecord */ | |
529 | LOCAL_FUNC | |
530 | void OTL_Get_ValueRecord( TT_Byte* value_record, | |
531 | TT_UShort value_format, | |
532 | TT_Byte* pos_table, | |
533 | OTL_ValueRecord* record ) | |
534 | { | |
535 | TT_Byte* p = value_record; | |
536 | ||
537 | /* clear vectors */ | |
538 | record->placement.x = 0; | |
539 | record->placement.y = 0; | |
540 | record->advance.x = 0; | |
541 | record->advance.y = 0; | |
542 | ||
543 | record->device_pla_x = 0; | |
544 | record->device_pla_y = 0; | |
545 | record->device_adv_x = 0; | |
546 | record->device_adv_y = 0; | |
547 | ||
548 | if (value_format & 1) record->placement.x = NEXT_Short(p); | |
549 | if (value_format & 2) record->placement.y = NEXT_Short(p); | |
550 | if (value_format & 4) record->advance.x = NEXT_Short(p); | |
551 | if (value_format & 8) record->advance.y = NEXT_Short(p); | |
552 | ||
553 | if (value_format & 16) record->device_pla_x = pos_table + NEXT_UShort(p); | |
554 | if (value_format & 32) record->device_pla_y = pos_table + NEXT_UShort(p); | |
555 | if (value_format & 64) record->device_adv_x = pos_table + NEXT_UShort(p); | |
556 | if (value_format & 128) record->device_adv_y = pos_table + NEXT_UShort(p); | |
557 | } | |
558 | ||
559 | ||
560 | ||
561 | /* extract Anchor */ | |
562 | LOCAL_FUNC | |
563 | void OTL_Get_Anchor( TT_Byte* anchor_table, | |
564 | OTL_Anchor* anchor ) | |
565 | { | |
566 | TT_Byte* p = anchor_table; | |
567 | ||
568 | anchor->format = NEXT_UShort(p); | |
569 | anchor->coord.x = NEXT_Short(p); | |
570 | anchor->coord.y = NEXT_Short(p); | |
571 | anchor->point = 0; | |
572 | anchor->device_x = 0; | |
573 | anchor->device_y = 0; | |
574 | ||
575 | switch (anchor->format) | |
576 | { | |
577 | case 2: | |
578 | anchor->point = NEXT_UShort(p); | |
579 | break; | |
580 | ||
581 | case 3: | |
582 | anchor->device_x = anchor_table + NEXT_UShort(p); | |
583 | anchor->device_y = anchor_table + NEXT_UShort(p); | |
584 | break; | |
585 | ||
586 | default: | |
587 | ; | |
588 | } | |
589 | } | |
590 | ||
591 | ||
592 | ||
593 | /* extract Mark from MarkArray */ | |
594 | LOCAL_FUNC | |
595 | void OTL_Get_Mark( TT_Byte* mark_array, | |
596 | TT_UInt index, | |
597 | TT_UShort* clazz, | |
598 | OTL_Anchor* anchor ) | |
599 | { | |
600 | TT_Byte* p = mark_array; | |
601 | TT_UInt count; | |
602 | ||
603 | *clazz = 0; | |
604 | MEM_Set( anchor, 0, sizeof(*anchor) ); | |
605 | ||
606 | count = NEXT_UShort(p); | |
607 | if (index < count) | |
608 | { | |
609 | p += 4*index; | |
610 | *clazz = NEXT_UShort(p); | |
611 | OTL_Get_Anchor( mark_array + NEXT_UShort(p), anchor ); | |
612 | } | |
613 | } | |
614 |