X-Git-Url: http://git.jankratochvil.net/?p=reactos.git;a=blobdiff_plain;f=lib%2Ffreetype%2Fsrc%2Fotlayout%2Fotlcommn.c;fp=lib%2Ffreetype%2Fsrc%2Fotlayout%2Fotlcommn.c;h=742ff5b36e1ae08bf64c029658d560dbff81392f;hp=0000000000000000000000000000000000000000;hb=7c0db166f81fbe8c8b913d7f26048e337d383605;hpb=e3ed2d773259cc445c7ff8181ebd934931365328 diff --git a/lib/freetype/src/otlayout/otlcommn.c b/lib/freetype/src/otlayout/otlcommn.c new file mode 100644 index 0000000..742ff5b --- /dev/null +++ b/lib/freetype/src/otlayout/otlcommn.c @@ -0,0 +1,940 @@ +/***************************************************************************/ +/* */ +/* otlcommn.c */ +/* */ +/* OpenType layout support, common tables (body). */ +/* */ +/* Copyright 2002 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otlayout.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_coverage_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p; + OTL_UInt format; + + + if ( table + 4 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + format = OTL_NEXT_USHORT( p ); + switch ( format ) + { + case 1: + { + OTL_UInt count = OTL_NEXT_USHORT( p ); + + + if ( p + count * 2 >= valid->limit ) + OTL_INVALID_TOO_SHORT; + + /* XXX: check glyph indices */ + } + break; + + case 2: + { + OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p ); + OTL_UInt start, end, start_cover, total = 0, last = 0; + + + if ( p + num_ranges * 6 >= valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( n = 0; n < num_ranges; n++ ) + { + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + start_cover = OTL_NEXT_USHORT( p ); + + if ( start > end || start_cover != total ) + OTL_INVALID_DATA; + + if ( n > 0 && start <= last ) + OTL_INVALID_DATA; + + total += end - start + 1; + last = end; + } + } + break; + + default: + OTL_INVALID_FORMAT; + } + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_coverage_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table; + OTL_UInt format = OTL_NEXT_USHORT( p ); + OTL_UInt count = OTL_NEXT_USHORT( p ); + OTL_UInt result = 0; + + + switch ( format ) + { + case 1: + return count; + + case 2: + { + OTL_UInt start, end; + + + for ( ; count > 0; count-- ) + { + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + p += 2; /* skip start_index */ + + result += end - start + 1; + } + } + break; + + default: + ; + } + + return result; + } + + + OTL_LOCALDEF( OTL_Int ) + otl_coverage_get_index( OTL_Bytes table, + OTL_UInt glyph_index ) + { + OTL_Bytes p = table; + OTL_UInt format = OTL_NEXT_USHORT( p ); + OTL_UInt count = OTL_NEXT_USHORT( p ); + + + switch ( format ) + { + case 1: + { + OTL_UInt min = 0, max = count, mid, gindex; + + + table += 4; + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = table + 2 * mid; + gindex = OTL_PEEK_USHORT( p ); + + if ( glyph_index == gindex ) + return (OTL_Int)mid; + + if ( glyph_index < gindex ) + max = mid; + else + min = mid + 1; + } + } + break; + + case 2: + { + OTL_UInt min = 0, max = count, mid; + OTL_UInt start, end, delta, start_cover; + + + table += 4; + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = table + 6 * mid; + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + + if ( glyph_index < start ) + max = mid; + else if ( glyph_index > end ) + min = mid + 1; + else + return (OTL_Int)( glyph_index + OTL_NEXT_USHORT( p ) - start ); + } + } + break; + + default: + ; + } + + return -1; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_class_definition_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt format; + + + if ( p + 4 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + format = OTL_NEXT_USHORT( p ); + switch ( format ) + { + case 1: + { + OTL_UInt count, start = OTL_NEXT_USHORT( p ); + + + if ( p + 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + count = OTL_NEXT_USHORT( p ); + + if ( p + count * 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + /* XXX: check glyph indices */ + } + break; + + case 2: + { + OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p ); + OTL_UInt start, end, value, last = 0; + + + if ( p + num_ranges * 6 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( n = 0; n < num_ranges; n++ ) + { + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + value = OTL_NEXT_USHORT( p ); /* ignored */ + + if ( start > end || ( n > 0 && start <= last ) ) + OTL_INVALID_DATA; + + last = end; + } + } + break; + + default: + OTL_INVALID_FORMAT; + } + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_class_definition_get_value( OTL_Bytes table, + OTL_UInt glyph_index ) + { + OTL_Bytes p = table; + OTL_UInt format = OTL_NEXT_USHORT( p ); + + + switch ( format ) + { + case 1: + { + OTL_UInt start = OTL_NEXT_USHORT( p ); + OTL_UInt count = OTL_NEXT_USHORT( p ); + OTL_UInt idx = (OTL_UInt)( glyph_index - start ); + + + if ( idx < count ) + { + p += 2 * idx; + return OTL_PEEK_USHORT( p ); + } + } + break; + + case 2: + { + OTL_UInt count = OTL_NEXT_USHORT( p ); + OTL_UInt min = 0, max = count, mid, gindex; + + + table += 4; + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = table + 6 * mid; + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + + if ( glyph_index < start ) + max = mid; + else if ( glyph_index > end ) + min = mid + 1; + else + return OTL_PEEK_USHORT( p ); + } + } + break; + + default: + ; + } + + return 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_device_table_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt start, end, count, format, count; + + + if ( p + 8 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + format = OTL_NEXT_USHORT( p ); + + if ( format < 1 || format > 3 || end < start ) + OTL_INVALID_DATA; + + count = (OTL_UInt)( end - start + 1 ); + + if ( p + ( ( 1 << format ) * count ) / 8 > valid->limit ) + OTL_INVALID_TOO_SHORT; + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_device_table_get_start( OTL_Bytes table ) + { + OTL_Bytes p = table; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_device_table_get_end( OTL_Bytes table ) + { + OTL_Bytes p = table + 2; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_Int ) + otl_device_table_get_delta( OTL_Bytes table, + OTL_UInt size ) + { + OTL_Bytes p = table; + OTL_Int result = 0; + OTL_UInt start, end, format, idx, value; + + + start = OTL_NEXT_USHORT( p ); + end = OTL_NEXT_USHORT( p ); + format = OTL_NEXT_USHORT( p ); + + if ( size >= start && size <= end ) + { + /* we could do that with clever bit operations, but a switch is */ + /* much simpler to understand and maintain */ + /* */ + switch ( format ) + { + case 1: + idx = (OTL_UInt)( ( size - start ) * 2 ); + p += idx / 16; + value = OTL_PEEK_USHORT( p ); + shift = idx & 15; + result = (OTL_Short)( value << shift ) >> ( 14 - shift ); + + break; + + case 2: + idx = (OTL_UInt)( ( size - start ) * 4 ); + p += idx / 16; + value = OTL_PEEK_USHORT( p ); + shift = idx & 15; + result = (OTL_Short)( value << shift ) >> ( 12 - shift ); + + break; + + case 3: + idx = (OTL_UInt)( ( size - start ) * 8 ); + p += idx / 16; + value = OTL_PEEK_USHORT( p ); + shift = idx & 15; + result = (OTL_Short)( value << shift ) >> ( 8 - shift ); + + break; + + default: + ; + } + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP LISTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_lookup_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt num_tables; + + + if ( table + 6 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + p += 4; + num_tables = OTL_NEXT_USHORT( p ); + + if ( p + num_tables * 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( ; num_tables > 0; num_tables-- ) + { + offset = OTL_NEXT_USHORT( p ); + + if ( table + offset >= valid->limit ) + OTL_INVALID_OFFSET; + } + + /* XXX: check sub-tables? */ + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_lookup_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table + 4; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_Bytes ) + otl_lookup_get_table( OTL_Bytes table, + OTL_UInt idx ) + { + OTL_Bytes p, result = NULL; + OTL_UInt count; + + + p = table + 4; + count = OTL_NEXT_USHORT( p ); + if ( idx < count ) + { + p += idx * 2; + result = table + OTL_PEEK_USHORT( p ); + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP LISTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_lookup_list_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table, q; + OTL_UInt num_lookups, offset; + + + if ( p + 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + num_lookups = OTL_NEXT_USHORT( p ); + + if ( p + num_lookups * 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( ; num_lookups > 0; num_lookups-- ) + { + offset = OTL_NEXT_USHORT( p ); + + otl_lookup_validate( table + offset, valid ); + } + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_lookup_list_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_Bytes ) + otl_lookup_list_get_lookup( OTL_Bytes table, + OTL_UInt idx ) + { + OTL_Bytes p, result = 0; + OTL_UInt count; + + + p = table; + count = OTL_NEXT_USHORT( p ); + if ( idx < count ) + { + p += idx * 2; + result = table + OTL_PEEK_USHORT( p ); + } + + return result; + } + + + OTL_LOCALDEF( OTL_Bytes ) + otl_lookup_list_get_table( OTL_Bytes table, + OTL_UInt lookup_index, + OTL_UInt table_index ) + { + OTL_Bytes result = NULL; + + + result = otl_lookup_list_get_lookup( table, lookup_index ); + if ( result ) + result = otl_lookup_get_table( result, table_index ); + + return result; + } + + + OTL_LOCALDEF( void ) + otl_lookup_list_foreach( OTL_Bytes table, + OTL_ForeachFunc func, + OTL_Pointer func_data ) + { + OTL_Bytes p = table; + OTL_UInt count = OTL_NEXT_USHORT( p ); + + + for ( ; count > 0; count-- ) + func( table + OTL_NEXT_USHORT( p ), func_data ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_feature_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt feat_params, num_lookups; + + + if ( p + 4 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + feat_params = OTL_NEXT_USHORT( p ); /* ignored */ + num_lookups = OTL_NEXT_USHORT( p ); + + if ( p + num_lookups * 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + /* XXX: check lookup indices */ + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_feature_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table + 4; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_feature_get_lookups( OTL_Bytes table, + OTL_UInt start, + OTL_UInt count, + OTL_UInt *lookups ) + { + OTL_Bytes p; + OTL_UInt num_features, result = 0; + + + p = table + 4; + num_features = OTL_NEXT_USHORT( p ); + + p += start * 2; + + for ( ; count > 0 && start < num_features; count--, start++ ) + { + lookups[0] = OTL_NEXT_USHORT(p); + lookups++; + result++; + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURE LIST *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + OTL_LOCALDEF( void ) + otl_feature_list_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt num_features, offset; + + + if ( table + 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + num_features = OTL_NEXT_USHORT( p ); + + if ( p + num_features * 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( ; num_features > 0; num_features-- ) + { + p += 4; /* skip tag */ + offset = OTL_NEXT_USHORT( p ); + + otl_feature_table_validate( table + offset, valid ); + } + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_feature_list_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_Bytes ) + otl_feature_list_get_feature( OTL_Bytes table, + OTL_UInt idx ) + { + OTL_Bytes p, result = NULL; + OTL_UInt count; + + + p = table; + count = OTL_NEXT_USHORT( p ); + + if ( idx < count ) + { + p += idx * 2; + result = table + OTL_PEEK_USHORT( p ); + } + + return result; + } + + + OTL_LOCALDEF( void ) + otl_feature_list_foreach( OTL_Bytes table, + OTL_ForeachFunc func, + OTL_Pointer func_data ) + { + OTL_Bytes p; + OTL_UInt count; + + + p = table; + count = OTL_NEXT_USHORT( p ); + + for ( ; count > 0; count-- ) + func( table + OTL_NEXT_USHORT( p ), func_data ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + OTL_LOCALDEF( void ) + otl_lang_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt lookup_order; + OTL_UInt req_feature; + OTL_UInt num_features; + + + if ( table + 6 >= valid->limit ) + OTL_INVALID_TOO_SHORT; + + lookup_order = OTL_NEXT_USHORT( p ); + req_feature = OTL_NEXT_USHORT( p ); + num_features = OTL_NEXT_USHORT( p ); + + /* XXX: check req_feature if not 0xFFFFU */ + + if ( p + 2 * num_features >= valid->limit ) + OTL_INVALID_TOO_SHORT; + + /* XXX: check features indices! */ + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_lang_get_count( OTL_Bytes table ) + { + OTL_Bytes p = table + 4; + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_lang_get_req_feature( OTL_Bytes table ) + { + OTL_Bytes p = table + 2; + + + return OTL_PEEK_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_lang_get_features( OTL_Bytes table, + OTL_UInt start, + OTL_UInt count, + OTL_UInt *features ) + { + OTL_Bytes p = table + 4; + OTL_UInt num_features = OTL_NEXT_USHORT( p ); + OTL_UInt result = 0; + + + p += start * 2; + + for ( ; count > 0 && start < num_features; start++, count-- ) + { + features[0] = OTL_NEXT_USHORT( p ); + features++; + result++; + } + + return result; + } + + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + OTL_LOCALDEF( void ) + otl_script_validate( OTL_Bytes table, + OTL_Validator valid ) + { + OTL_UInt default_lang; + OTL_Bytes p = table; + + + if ( table + 4 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + default_lang = OTL_NEXT_USHORT( p ); + num_langs = OTL_NEXT_USHORT( p ); + + if ( default_lang != 0 ) + { + if ( table + default_lang >= valid->limit ) + OTL_INVALID_OFFSET; + } + + if ( p + num_langs * 6 >= valid->limit ) + OTL_INVALID_OFFSET; + + for ( ; num_langs > 0; num_langs-- ) + { + OTL_UInt offset; + + + p += 4; /* skip tag */ + offset = OTL_NEXT_USHORT( p ); + + otl_lang_validate( table + offset, valid ); + } + } + + + OTL_LOCALDEF( void ) + otl_script_list_validate( OTL_Bytes list, + OTL_Validator valid ) + { + OTL_UInt num_scripts; + OTL_Bytes p = list; + + + if ( list + 2 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + num_scripts = OTL_NEXT_USHORT( p ); + + if ( p + num_scripts * 6 > valid->limit ) + OTL_INVALID_TOO_SHORT; + + for ( ; num_scripts > 0; num_scripts-- ) + { + OTL_UInt offset; + + + p += 4; /* skip tag */ + offset = OTL_NEXT_USHORT( p ); + + otl_script_table_validate( list + offset, valid ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP LISTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otl_lookup_table_validate( OTL_Bytes table, + OTL_UInt type_count, + OTL_ValidateFunc* type_funcs, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt lookup_type, lookup_flag, count; + OTL_ValidateFunc validate; + + OTL_CHECK( 6 ); + lookup_type = OTL_NEXT_USHORT( p ); + lookup_flag = OTL_NEXT_USHORT( p ); + count = OTL_NEXT_USHORT( p ); + + if ( lookup_type == 0 || lookup_type >= type_count ) + OTL_INVALID_DATA; + + validate = type_funcs[ lookup_type - 1 ]; + + OTL_CHECK( 2*count ); + for ( ; count > 0; count-- ) + validate( table + OTL_NEXT_USHORT( p ), valid ); + } + + + OTL_LOCALDEF( void ) + otl_lookup_list_validate( OTL_Bytes table, + OTL_UInt type_count, + OTL_ValidateFunc* type_funcs, + OTL_Validator valid ) + { + OTL_Bytes p = table; + OTL_UInt count; + + OTL_CHECK( 2 ); + count = OTL_NEXT_USHORT( p ); + + OTL_CHECK( 2*count ); + for ( ; count > 0; count-- ) + otl_lookup_table_validate( table + OTL_NEXT_USHORT( p ), + type_count, type_funcs, valid ); + } + +/* END */