tt_size_init( FT_Size ttsize ) /* TT_Size */ { TT_Size size = (TT_Size)ttsize; FT_Error error = TT_Err_Ok; #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER TT_Face face = (TT_Face)size->root.face; FT_Memory memory = face->root.memory; FT_Int i; FT_UShort n_twilight; TT_MaxProfile* maxp = &face->max_profile; size->max_function_defs = maxp->maxFunctionDefs; size->max_instruction_defs = maxp->maxInstructionDefs; size->num_function_defs = 0; size->num_instruction_defs = 0; size->max_func = 0; size->max_ins = 0; size->cvt_size = face->cvt_size; size->storage_size = maxp->maxStorage; /* Set default metrics */ { FT_Size_Metrics* metrics = &size->root.metrics; TT_Size_Metrics* metrics2 = &size->ttmetrics; metrics->x_ppem = 0; metrics->y_ppem = 0; metrics2->rotated = FALSE; metrics2->stretched = FALSE; /* set default compensation (all 0) */ for ( i = 0; i < 4; i++ ) metrics2->compensations[i] = 0; } /* allocate function defs, instruction defs, cvt, and storage area */ if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || FT_NEW_ARRAY( size->cvt, size->cvt_size ) || FT_NEW_ARRAY( size->storage, size->storage_size ) ) { tt_size_done( ttsize ); return error; } /* reserve twilight zone */ n_twilight = maxp->maxTwilightPoints; /* there are 4 phantom points (do we need this?) */ n_twilight += 4; error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); if ( error ) { tt_size_done( ttsize ); return error; } size->twilight.n_points = n_twilight; size->GS = tt_default_graphics_state; /* set `face->interpreter' according to the debug hook present */ { FT_Library library = face->root.driver->root.library; face->interpreter = (TT_Interpreter) library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; if ( !face->interpreter ) face->interpreter = (TT_Interpreter)TT_RunIns; } /* Fine, now run the font program! */ error = tt_size_run_fpgm( size ); if ( error ) tt_size_done( ttsize ); #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ size->ttmetrics.valid = FALSE; size->strike_index = 0xFFFFFFFFUL; return error; }
static void t42_parse_encoding( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Byte* cur; FT_Byte* limit = parser->root.limit; PSAux_Service psaux = (PSAux_Service)face->psaux; T1_Skip_Spaces( parser ); cur = parser->root.cursor; if ( cur >= limit ) { FT_ERROR(( "t42_parse_encoding: out of bounds!\n" )); parser->root.error = T42_Err_Invalid_File_Format; return; } /* if we have a number or `[', the encoding is an array, */ /* and we must load it now */ if ( ft_isdigit( *cur ) || *cur == '[' ) { T1_Encoding encode = &face->type1.encoding; FT_UInt count, n; PS_Table char_table = &loader->encoding_table; FT_Memory memory = parser->root.memory; FT_Error error; FT_Bool only_immediates = 0; /* read the number of entries in the encoding; should be 256 */ if ( *cur == '[' ) { count = 256; only_immediates = 1; parser->root.cursor++; } else count = (FT_UInt)T1_ToInt( parser ); T1_Skip_Spaces( parser ); if ( parser->root.cursor >= limit ) return; /* we use a T1_Table to store our charnames */ loader->num_chars = encode->num_chars = count; if ( FT_NEW_ARRAY( encode->char_index, count ) || FT_NEW_ARRAY( encode->char_name, count ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, count, memory ) ) ) { parser->root.error = error; return; } /* We need to `zero' out encoding_table.elements */ for ( n = 0; n < count; n++ ) { char* notdef = (char *)".notdef"; T1_Add_Table( char_table, n, notdef, 8 ); } /* Now we need to read records of the form */ /* */ /* ... charcode /charname ... */ /* */ /* for each entry in our table. */ /* */ /* We simply look for a number followed by an immediate */ /* name. Note that this ignores correctly the sequence */ /* that is often seen in type42 fonts: */ /* */ /* 0 1 255 { 1 index exch /.notdef put } for dup */ /* */ /* used to clean the encoding array before anything else. */ /* */ /* Alternatively, if the array is directly given as */ /* */ /* /Encoding [ ... ] */ /* */ /* we only read immediates. */ n = 0; T1_Skip_Spaces( parser ); while ( parser->root.cursor < limit ) { cur = parser->root.cursor; /* we stop when we encounter `def' or `]' */ if ( *cur == 'd' && cur + 3 < limit ) { if ( cur[1] == 'e' && cur[2] == 'f' && t42_is_space( cur[3] ) ) { FT_TRACE6(( "encoding end\n" )); cur += 3; break; } } if ( *cur == ']' ) { FT_TRACE6(( "encoding end\n" )); cur++; break; } /* check whether we have found an entry */ if ( ft_isdigit( *cur ) || only_immediates ) { FT_Int charcode; if ( only_immediates ) charcode = n; else { charcode = (FT_Int)T1_ToInt( parser ); T1_Skip_Spaces( parser ); } cur = parser->root.cursor; if ( *cur == '/' && cur + 2 < limit && n < count ) { FT_PtrDist len; cur++; parser->root.cursor = cur; T1_Skip_PS_Token( parser ); if ( parser->root.error ) return; len = parser->root.cursor - cur; parser->root.error = T1_Add_Table( char_table, charcode, cur, len + 1 ); if ( parser->root.error ) return; char_table->elements[charcode][len] = '\0'; n++; } } else { T1_Skip_PS_Token( parser ); if ( parser->root.error ) return; } T1_Skip_Spaces( parser ); } face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; parser->root.cursor = cur; } /* Otherwise, we should have either `StandardEncoding', */ /* `ExpertEncoding', or `ISOLatin1Encoding' */ else { if ( cur + 17 < limit && ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; else if ( cur + 15 < limit && ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; else if ( cur + 18 < limit && ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; else { FT_ERROR(( "t42_parse_encoding: invalid token!\n" )); parser->root.error = T42_Err_Invalid_File_Format; } } }
/* Builds a table that maps Unicode values to glyph indices */ static FT_Error ps_unicodes_init( FT_Memory memory, FT_UInt num_glyphs, const char** glyph_names, PS_Unicodes* table ) { FT_Error error; /* we first allocate the table */ table->num_maps = 0; table->maps = 0; if ( !FT_NEW_ARRAY( table->maps, num_glyphs ) ) { FT_UInt n; FT_UInt count; PS_UniMap* map; FT_UInt32 uni_char; map = table->maps; for ( n = 0; n < num_glyphs; n++ ) { const char* gname = glyph_names[n]; if ( gname ) { uni_char = ps_unicode_value( gname ); if ( uni_char != 0 && uni_char != 0xFFFFL ) { map->unicode = (FT_UInt)uni_char; map->glyph_index = n; map++; } } } /* now, compress the table a bit */ count = (FT_UInt)( map - table->maps ); if ( count > 0 && FT_REALLOC( table->maps, num_glyphs * sizeof ( PS_UniMap ), count * sizeof ( PS_UniMap ) ) ) count = 0; if ( count == 0 ) { FT_FREE( table->maps ); if ( !error ) error = PSnames_Err_Invalid_Argument; /* no unicode chars here! */ } else /* sort the table in increasing order of unicode values */ ft_qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps ); table->num_maps = count; } return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error; FT_Memory memory = FT_FACE( face )->memory; FT_ULong format, size; PCF_Metric metrics = 0; FT_ULong nmetrics, i; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; if ( FT_READ_ULONG_LE( format ) ) goto Bail; if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return FT_THROW( Invalid_File_Format ); if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error ) return FT_THROW( Invalid_File_Format ); face->nmetrics = nmetrics; if ( !nmetrics ) return FT_THROW( Invalid_Table ); FT_TRACE4(( "pcf_get_metrics:\n" )); FT_TRACE4(( " number of metrics: %d\n", nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( nmetrics > size / PCF_METRIC_SIZE ) return FT_THROW( Invalid_Table ); } else { if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) return FT_THROW( Invalid_Table ); } if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return FT_THROW( Out_Of_Memory ); metrics = face->metrics; for ( i = 0; i < nmetrics; i++, metrics++ ) { error = pcf_get_metric( stream, format, metrics ); metrics->bits = 0; FT_TRACE5(( " idx %d: width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, metrics->characterWidth, metrics->leftSideBearing, metrics->rightSideBearing, metrics->ascent, metrics->descent, metrics->attributes )); if ( error ) break; /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ /* compute a glyph's bitmap dimensions, thus setting them to zero in */ /* case of an error disables this particular glyph only */ if ( metrics->rightSideBearing < metrics->leftSideBearing || metrics->ascent + metrics->descent < 0 ) { metrics->characterWidth = 0; metrics->leftSideBearing = 0; metrics->rightSideBearing = 0; metrics->ascent = 0; metrics->descent = 0; FT_TRACE0(( "pcf_get_metrics:" " invalid metrics for glyph %d\n", i )); } } if ( error ) FT_FREE( face->metrics ); Bail: return error; }
static FT_Error pcf_get_encodings( FT_Stream stream, PCF_Face face ) { FT_Error error; FT_Memory memory = FT_FACE( face )->memory; FT_ULong format, size; int firstCol, lastCol; int firstRow, lastRow; int nencoding, encodingOffset; int i, j, k; PCF_Encoding encoding = NULL; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BDF_ENCODINGS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 14 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { firstCol = FT_GET_SHORT(); lastCol = FT_GET_SHORT(); firstRow = FT_GET_SHORT(); lastRow = FT_GET_SHORT(); face->defaultChar = FT_GET_SHORT(); } else { firstCol = FT_GET_SHORT_LE(); lastCol = FT_GET_SHORT_LE(); firstRow = FT_GET_SHORT_LE(); lastRow = FT_GET_SHORT_LE(); face->defaultChar = FT_GET_SHORT_LE(); } FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return FT_THROW( Invalid_File_Format ); /* sanity checks */ if ( firstCol < 0 || firstCol > lastCol || lastCol > 0xFF || firstRow < 0 || firstRow > lastRow || lastRow > 0xFF ) return FT_THROW( Invalid_Table ); FT_TRACE4(( "pdf_get_encodings:\n" )); FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", firstCol, lastCol, firstRow, lastRow )); nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); if ( FT_NEW_ARRAY( encoding, nencoding ) ) return FT_THROW( Out_Of_Memory ); error = FT_Stream_EnterFrame( stream, 2 * nencoding ); if ( error ) goto Bail; k = 0; for ( i = firstRow; i <= lastRow; i++ ) { for ( j = firstCol; j <= lastCol; j++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) encodingOffset = FT_GET_SHORT(); else encodingOffset = FT_GET_SHORT_LE(); if ( encodingOffset != -1 ) { encoding[k].enc = i * 256 + j; encoding[k].glyph = (FT_Short)encodingOffset; FT_TRACE5(( " code %d (0x%04X): idx %d\n", encoding[k].enc, encoding[k].enc, encoding[k].glyph )); k++; } } } FT_Stream_ExitFrame( stream ); if ( FT_RENEW_ARRAY( encoding, nencoding, k ) ) goto Bail; face->nencodings = k; face->encodings = encoding; return error; Bail: FT_FREE( encoding ); return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format, size; PCF_Metric metrics = 0; FT_ULong nmetrics, i; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; if ( FT_READ_ULONG_LE( format ) ) goto Bail; if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return PCF_Err_Invalid_File_Format; if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error ) return PCF_Err_Invalid_File_Format; face->nmetrics = nmetrics; if ( !nmetrics ) return PCF_Err_Invalid_Table; FT_TRACE4(( "pcf_get_metrics:\n" )); FT_TRACE4(( " number of metrics: %d\n", nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( nmetrics > size / PCF_METRIC_SIZE ) return PCF_Err_Invalid_Table; } else { if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) return PCF_Err_Invalid_Table; } if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return PCF_Err_Out_Of_Memory; metrics = face->metrics; for ( i = 0; i < nmetrics; i++ ) { error = pcf_get_metric( stream, format, metrics + i ); metrics[i].bits = 0; FT_TRACE5(( " idx %d: width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, ( metrics + i )->characterWidth, ( metrics + i )->leftSideBearing, ( metrics + i )->rightSideBearing, ( metrics + i )->ascent, ( metrics + i )->descent, ( metrics + i )->attributes )); if ( error ) break; } if ( error ) FT_FREE( face->metrics ); Bail: return error; }
static FT_Error pcf_read_TOC( FT_Stream stream, PCF_Face face ) { FT_Error error; PCF_Toc toc = &face->toc; PCF_Table tables; FT_Memory memory = FT_FACE(face)->memory; FT_UInt n; if ( FT_STREAM_SEEK ( 0 ) || FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) return PCF_Err_Cannot_Open_Resource; if ( toc->version != PCF_FILE_VERSION || toc->count > FT_ARRAY_MAX( face->toc.tables ) || toc->count == 0 ) return PCF_Err_Invalid_File_Format; if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) return PCF_Err_Out_Of_Memory; tables = face->toc.tables; for ( n = 0; n < toc->count; n++ ) { if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) goto Exit; tables++; } /* Sort tables and check for overlaps. Because they are almost */ /* always ordered already, an in-place bubble sort with simultaneous */ /* boundary checking seems appropriate. */ tables = face->toc.tables; for ( n = 0; n < toc->count - 1; n++ ) { FT_UInt i, have_change; have_change = 0; for ( i = 0; i < toc->count - 1 - n; i++ ) { PCF_TableRec tmp; if ( tables[i].offset > tables[i + 1].offset ) { tmp = tables[i]; tables[i] = tables[i + 1]; tables[i + 1] = tmp; have_change = 1; } if ( ( tables[i].size > tables[i + 1].offset ) || ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) return PCF_Err_Invalid_Offset; } if ( !have_change ) break; } #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt i, j; const char* name = "?"; FT_TRACE4(( "pcf_read_TOC:\n" )); FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); tables = face->toc.tables; for ( i = 0; i < toc->count; i++ ) { for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ ) if ( tables[i].type == (FT_UInt)( 1 << j ) ) name = tableNames[j]; FT_TRACE4(( " %d: type=%s, format=0x%X, " "size=%ld (0x%lX), offset=%ld (0x%lX)\n", i, name, tables[i].format, tables[i].size, tables[i].size, tables[i].offset, tables[i].offset )); } } #endif return PCF_Err_Ok; Exit: FT_FREE( face->toc.tables ); return error; }
/* entries to C-style strings (this is, NULL-terminated). */ static FT_Error cff_index_get_pointers( CFF_Index idx, FT_Byte*** table, FT_Byte** pool ) { FT_Error error = FT_Err_Ok; FT_Memory memory = idx->stream->memory; FT_Byte** t = NULL; FT_Byte* new_bytes = NULL; *table = NULL; if ( idx->offsets == NULL ) { error = cff_index_load_offsets( idx ); if ( error ) goto Exit; } if ( idx->count > 0 && !FT_NEW_ARRAY( t, idx->count + 1 ) && ( !pool || !FT_ALLOC( new_bytes, idx->data_size + idx->count ) ) ) { FT_ULong n, cur_offset; FT_ULong extra = 0; FT_Byte* org_bytes = idx->bytes; /* at this point, `idx->offsets' can't be NULL */ cur_offset = idx->offsets[0] - 1; /* sanity check */ if ( cur_offset != 0 ) { FT_TRACE0(( "cff_index_get_pointers:" " invalid first offset value %d set to zero\n", cur_offset )); cur_offset = 0; } if ( !pool ) t[0] = org_bytes + cur_offset; else t[0] = new_bytes + cur_offset; for ( n = 1; n <= idx->count; n++ ) { FT_ULong next_offset = idx->offsets[n] - 1; /* two sanity checks for invalid offset tables */ if ( next_offset < cur_offset ) next_offset = cur_offset; else if ( next_offset > idx->data_size ) next_offset = idx->data_size; if ( !pool ) t[n] = org_bytes + next_offset; else { t[n] = new_bytes + next_offset + extra; if ( next_offset != cur_offset ) { FT_MEM_COPY( t[n - 1], org_bytes + cur_offset, t[n] - t[n - 1] ); t[n][0] = '\0'; t[n] += 1; extra++; } } cur_offset = next_offset; } *table = t; if ( pool ) *pool = new_bytes; } Exit: return error; }
static FT_Error cff_charset_load( CFF_Charset charset, FT_UInt num_glyphs, FT_Stream stream, FT_ULong base_offset, FT_ULong offset, FT_Bool invert ) { FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; FT_UShort glyph_sid; /* If the the offset is greater than 2, we have to parse the */ /* charset table. */ if ( offset > 2 ) { FT_UInt j; charset->offset = base_offset + offset; /* Get the format of the table. */ if ( FT_STREAM_SEEK( charset->offset ) || FT_READ_BYTE( charset->format ) ) goto Exit; /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* assign the .notdef glyph */ charset->sids[0] = 0; switch ( charset->format ) { case 0: if ( num_glyphs > 0 ) { if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) goto Exit; for ( j = 1; j < num_glyphs; j++ ) charset->sids[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); } break; case 1: case 2: { FT_UInt nleft; FT_UInt i; j = 1; while ( j < num_glyphs ) { /* Read the first glyph sid of the range. */ if ( FT_READ_USHORT( glyph_sid ) ) goto Exit; /* Read the number of glyphs in the range. */ if ( charset->format == 2 ) { if ( FT_READ_USHORT( nleft ) ) goto Exit; } else { if ( FT_READ_BYTE( nleft ) ) goto Exit; } /* try to rescue some of the SIDs if `nleft' is too large */ if ( glyph_sid > 0xFFFFL - nleft ) { FT_ERROR(( "cff_charset_load: invalid SID range trimmed" " nleft=%d -> %d\n", nleft, 0xFFFFL - glyph_sid )); nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); } /* Fill in the range of sids -- `nleft + 1' glyphs. */ for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) charset->sids[j] = glyph_sid; } } break; default: FT_ERROR(( "cff_charset_load: invalid table format\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } } else { /* Parse default tables corresponding to offset == 0, 1, or 2. */ /* CFF specification intimates the following: */ /* */ /* In order to use a predefined charset, the following must be */ /* true: The charset constructed for the glyphs in the font's */ /* charstrings dictionary must match the predefined charset in */ /* the first num_glyphs. */ charset->offset = offset; /* record charset type */ switch ( (FT_UInt)offset ) { case 0: if ( num_glyphs > 229 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe ISO-Latin)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); break; case 1: if ( num_glyphs > 166 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); break; case 2: if ( num_glyphs > 87 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert Subset)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); break; default: error = FT_THROW( Invalid_File_Format ); goto Exit; } } /* we have to invert the `sids' array for subsetted CID-keyed fonts */ if ( invert ) error = cff_charset_compute_cids( charset, num_glyphs, memory ); Exit: /* Clean up if there was an error. */ if ( error ) { FT_FREE( charset->sids ); FT_FREE( charset->cids ); charset->format = 0; charset->offset = 0; charset->sids = 0; } return error; }
static FT_Error FNT_Face_Init( FT_Stream stream, FNT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; FT_Memory memory = FT_FACE_MEMORY( face ); FT_UNUSED( num_params ); FT_UNUSED( params ); /* try to load font from a DLL */ error = fnt_face_get_dll_font( face, face_index ); if ( error ) { /* this didn't work; try to load a single FNT font */ FNT_Font font; if ( FT_NEW( face->font ) ) goto Exit; face->root.num_faces = 1; font = face->font; font->offset = 0; font->fnt_size = stream->size; error = fnt_font_load( font, stream ); if ( error ) goto Fail; } /* we now need to fill the root FT_Face fields */ /* with relevant information */ { FT_Face root = FT_FACE( face ); FNT_Font font = face->font; root->face_flags = FT_FACE_FLAG_FIXED_SIZES | FT_FACE_FLAG_HORIZONTAL; if ( font->header.avg_width == font->header.max_width ) root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; if ( font->header.italic ) root->style_flags |= FT_STYLE_FLAG_ITALIC; if ( font->header.weight >= 800 ) root->style_flags |= FT_STYLE_FLAG_BOLD; /* set up the `fixed_sizes' array */ if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) goto Fail; root->num_fixed_sizes = 1; { FT_Bitmap_Size* bsize = root->available_sizes; bsize->width = font->header.avg_width; bsize->height = font->header.pixel_height + font->header.external_leading; bsize->size = font->header.nominal_point_size << 6; bsize->x_ppem = (FT_Pos)( ( font->header.horizontal_resolution * bsize->size + 36 ) / 72 ); bsize->y_ppem = (FT_Pos)( ( font->header.vertical_resolution* bsize->size + 36 ) / 72 ); } { FT_CharMapRec charmap; charmap.encoding = FT_ENCODING_UNICODE; charmap.platform_id = 3; charmap.encoding_id = 1; charmap.face = root; error = FT_CMap_New( fnt_cmap_class, NULL, &charmap, NULL ); if ( error ) goto Fail; /* Select default charmap */ if ( root->num_charmaps ) root->charmap = root->charmaps[0]; } /* setup remaining flags */ /* reserve one slot for the .notdef glyph at index 0 */ root->num_glyphs = font->header.last_char - font->header.first_char + 1 + 1; root->family_name = (FT_String*)font->fnt_frame + font->header.face_name_offset; root->style_name = (char *)"Regular"; if ( root->style_flags & FT_STYLE_FLAG_BOLD ) { if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) root->style_name = (char *)"Bold Italic"; else root->style_name = (char *)"Bold"; } else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) root->style_name = (char *)"Italic"; } Fail: if ( error ) FNT_Face_Done( face ); Exit: return error; }
cff_font_load( FT_Library library, FT_Stream stream, FT_Int face_index, CFF_Font font, FT_Bool pure_cff ) { static const FT_Frame_Field cff_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE CFF_FontRec FT_FRAME_START( 4 ), FT_FRAME_BYTE( version_major ), FT_FRAME_BYTE( version_minor ), FT_FRAME_BYTE( header_size ), FT_FRAME_BYTE( absolute_offsize ), FT_FRAME_END }; FT_Error error; FT_Memory memory = stream->memory; FT_ULong base_offset; CFF_FontRecDict dict; CFF_IndexRec string_index; FT_UInt subfont_index; FT_ZERO( font ); FT_ZERO( &string_index ); font->stream = stream; font->memory = memory; dict = &font->top_font.font_dict; base_offset = FT_STREAM_POS(); /* read CFF font header */ if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) goto Exit; /* check format */ if ( font->version_major != 1 || font->header_size < 4 || font->absolute_offsize > 4 ) { FT_TRACE2(( " not a CFF font header\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } /* skip the rest of the header */ if ( FT_STREAM_SKIP( font->header_size - 4 ) ) goto Exit; /* read the name, top dict, string and global subrs index */ if ( FT_SET_ERROR( cff_index_init( &font->name_index, stream, 0 ) ) || FT_SET_ERROR( cff_index_init( &font->font_dict_index, stream, 0 ) ) || FT_SET_ERROR( cff_index_init( &string_index, stream, 1 ) ) || FT_SET_ERROR( cff_index_init( &font->global_subrs_index, stream, 1 ) ) || FT_SET_ERROR( cff_index_get_pointers( &string_index, &font->strings, &font->string_pool ) ) ) goto Exit; font->num_strings = string_index.count; if ( pure_cff ) { /* well, we don't really forget the `disabled' fonts... */ subfont_index = (FT_UInt)( face_index & 0xFFFF ); if ( face_index > 0 && subfont_index >= font->name_index.count ) { FT_ERROR(( "cff_font_load:" " invalid subfont index for pure CFF font (%d)\n", subfont_index )); error = FT_THROW( Invalid_Argument ); goto Exit; } font->num_faces = font->name_index.count; } else { subfont_index = 0; if ( font->name_index.count > 1 ) { FT_ERROR(( "cff_font_load:" " invalid CFF font with multiple subfonts\n" " " " in SFNT wrapper\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } } /* in case of a font format check, simply exit now */ if ( face_index < 0 ) goto Exit; /* now, parse the top-level font dictionary */ FT_TRACE4(( "parsing top-level\n" )); error = cff_subfont_load( &font->top_font, &font->font_dict_index, subfont_index, stream, base_offset, library ); if ( error ) goto Exit; if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) goto Exit; error = cff_index_init( &font->charstrings_index, stream, 0 ); if ( error ) goto Exit; /* now, check for a CID font */ if ( dict->cid_registry != 0xFFFFU ) { CFF_IndexRec fd_index; CFF_SubFont sub = NULL; FT_UInt idx; /* this is a CID-keyed font, we must now allocate a table of */ /* sub-fonts, then load each of them separately */ if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) goto Exit; error = cff_index_init( &fd_index, stream, 0 ); if ( error ) goto Exit; if ( fd_index.count > CFF_MAX_CID_FONTS ) { FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" )); goto Fail_CID; } /* allocate & read each font dict independently */ font->num_subfonts = fd_index.count; if ( FT_NEW_ARRAY( sub, fd_index.count ) ) goto Fail_CID; /* set up pointer table */ for ( idx = 0; idx < fd_index.count; idx++ ) font->subfonts[idx] = sub + idx; /* now load each subfont independently */ for ( idx = 0; idx < fd_index.count; idx++ ) { sub = font->subfonts[idx]; FT_TRACE4(( "parsing subfont %u\n", idx )); error = cff_subfont_load( sub, &fd_index, idx, stream, base_offset, library ); if ( error ) goto Fail_CID; } /* now load the FD Select array */ error = CFF_Load_FD_Select( &font->fd_select, font->charstrings_index.count, stream, base_offset + dict->cid_fd_select_offset ); Fail_CID: cff_index_done( &fd_index ); if ( error ) goto Exit; } else font->num_subfonts = 0; /* read the charstrings index now */ if ( dict->charstrings_offset == 0 ) { FT_ERROR(( "cff_font_load: no charstrings offset\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } font->num_glyphs = font->charstrings_index.count; error = cff_index_get_pointers( &font->global_subrs_index, &font->global_subrs, NULL ); if ( error ) goto Exit; /* read the Charset and Encoding tables if available */ if ( font->num_glyphs > 0 ) { FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff ); error = cff_charset_load( &font->charset, font->num_glyphs, stream, base_offset, dict->charset_offset, invert ); if ( error ) goto Exit; /* CID-keyed CFFs don't have an encoding */ if ( dict->cid_registry == 0xFFFFU ) { error = cff_encoding_load( &font->encoding, &font->charset, font->num_glyphs, stream, base_offset, dict->encoding_offset ); if ( error ) goto Exit; } } /* get the font name (/CIDFontName for CID-keyed fonts, */ /* /FontName otherwise) */ font->font_name = cff_index_get_name( font, subfont_index ); Exit: cff_index_done( &string_index ); return error; }
/* We do this only if bytecode interpretation is really needed. */ static FT_Error tt_size_init_bytecode( FT_Size ftsize, FT_Bool pedantic ) { FT_Error error; TT_Size size = (TT_Size)ftsize; TT_Face face = (TT_Face)ftsize->face; FT_Memory memory = face->root.memory; FT_UShort n_twilight; TT_MaxProfile* maxp = &face->max_profile; /* clean up bytecode related data */ FT_FREE( size->function_defs ); FT_FREE( size->instruction_defs ); FT_FREE( size->cvt ); FT_FREE( size->storage ); if ( size->context ) TT_Done_Context( size->context ); tt_glyphzone_done( &size->twilight ); size->bytecode_ready = -1; size->cvt_ready = -1; size->context = TT_New_Context( (TT_Driver)face->root.driver ); size->max_function_defs = maxp->maxFunctionDefs; size->max_instruction_defs = maxp->maxInstructionDefs; size->num_function_defs = 0; size->num_instruction_defs = 0; size->max_func = 0; size->max_ins = 0; size->cvt_size = face->cvt_size; size->storage_size = maxp->maxStorage; /* Set default metrics */ { TT_Size_Metrics* tt_metrics = &size->ttmetrics; tt_metrics->rotated = FALSE; tt_metrics->stretched = FALSE; /* set default engine compensation */ tt_metrics->compensations[0] = 0; /* gray */ tt_metrics->compensations[1] = 0; /* black */ tt_metrics->compensations[2] = 0; /* white */ tt_metrics->compensations[3] = 0; /* reserved */ } /* allocate function defs, instruction defs, cvt, and storage area */ if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || FT_NEW_ARRAY( size->cvt, size->cvt_size ) || FT_NEW_ARRAY( size->storage, size->storage_size ) ) goto Exit; /* reserve twilight zone */ n_twilight = maxp->maxTwilightPoints; /* there are 4 phantom points (do we need this?) */ n_twilight += 4; error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); if ( error ) goto Exit; size->twilight.n_points = n_twilight; size->GS = tt_default_graphics_state; /* set `face->interpreter' according to the debug hook present */ { FT_Library library = face->root.driver->root.library; face->interpreter = (TT_Interpreter) library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; if ( !face->interpreter ) face->interpreter = (TT_Interpreter)TT_RunIns; } /* Fine, now run the font program! */ /* In case of an error while executing `fpgm', we intentionally don't */ /* clean up immediately – bugs in the `fpgm' are so fundamental that */ /* all following hinting calls should fail. Additionally, `fpgm' is */ /* to be executed just once; calling it again is completely useless */ /* and might even lead to extremely slow behaviour if it is malformed */ /* (containing an infinite loop, for example). */ error = tt_size_run_fpgm( size, pedantic ); return error; Exit: if ( error ) tt_size_done_bytecode( ftsize ); return error; }
sfnt_load_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_Error psnames_error; #endif FT_Bool has_outline; FT_Bool is_apple_sbit; FT_Bool ignore_preferred_family = FALSE; FT_Bool ignore_preferred_subfamily = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED( face_index ); /* Check parameters */ { FT_Int i; for ( i = 0; i < num_params; i++ ) { if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) ignore_preferred_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) ignore_preferred_subfamily = TRUE; } } /* Load tables */ /* We now support two SFNT-based bitmapped font formats. They */ /* are recognized easily as they do not include a `glyf' */ /* table. */ /* */ /* The first format comes from Apple, and uses a table named */ /* `bhed' instead of `head' to store the font header (using */ /* the same format). It also doesn't include horizontal and */ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ /* missing). */ /* */ /* The other format comes from Microsoft, and is used with */ /* WinCE/PocketPC. It looks like a standard TTF, except that */ /* it doesn't contain outlines. */ /* */ FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #else has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #endif is_apple_sbit = 0; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if ( !has_outline && sfnt->load_bhed ) { LOAD_( bhed ); is_apple_sbit = FT_BOOL( !error ); } /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { LOAD_( head ); if ( error ) goto Exit; } if ( face->header.Units_Per_EM == 0 ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ LOAD_( maxp ); LOAD_( cmap ); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ LOAD_( name ); LOAD_( post ); #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES psnames_error = error; #endif /* do not load the metrics headers and tables if this is an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { /* load the `hhea' and `hmtx' tables */ LOADM_( hhea, 0 ); if ( !error ) { LOADM_( hmtx, 0 ); if ( FT_ERR_EQ( error, Table_Missing ) ) { error = FT_THROW( Hmtx_Table_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hmtx' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } else if ( FT_ERR_EQ( error, Table_Missing ) ) { /* No `hhea' table necessary for SFNT Mac fonts. */ if ( face->format_tag == TTAG_true ) { FT_TRACE2(( "This is an SFNT Mac font.\n" )); has_outline = 0; error = FT_Err_Ok; } else { error = FT_THROW( Horiz_Header_Missing ); #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hhea' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = FT_Err_Ok; } #endif } } if ( error ) goto Exit; /* try to load the `vhea' and `vmtx' tables */ LOADM_( hhea, 1 ); if ( !error ) { LOADM_( hmtx, 1 ); if ( !error ) face->vertical_info = 1; } if ( error && FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; LOAD_( os2 ); if ( error ) { /* we treat the table as missing if there are any errors */ face->os2.version = 0xFFFFU; } } /* the optional tables */ /* embedded bitmap support */ if ( sfnt->load_eblc ) { LOAD_( eblc ); if ( error ) { /* a font which contains neither bitmaps nor outlines is */ /* still valid (although rather useless in most cases); */ /* however, you can find such stripped fonts in PDFs */ if ( FT_ERR_EQ( error, Table_Missing ) ) error = FT_Err_Ok; else goto Exit; } } LOAD_( pclt ); if ( error ) { if ( FT_ERR_NEQ( error, Table_Missing ) ) goto Exit; face->pclt.Version = 0; } /* consider the kerning and gasp tables as optional */ LOAD_( gasp ); LOAD_( kern ); face->root.num_glyphs = face->max_profile.numGlyphs; /* FreeType don't have generalized method which distinguish Arial Black from Arial. */ /* In our QtWebKit for Windows FreeType edition, the problem cause using Arial Black font */ /* when a content have "font-family: Arial". */ /* The Arial problem due to Arial and Arial Black return "Arial" as preferred family. */ /* We read font family, not preferred family, for the workaround. */ /* The newer freetype have ignore preferred option. */ /* The optiom may fix this bug, but you should consider WWS family. */ GET_NAME( FONT_FAMILY, &face->root.family_name ); GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); /* now set up root fields */ { FT_Face root = &face->root; FT_Long flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if ( has_outline == TRUE ) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if ( !psnames_error && face->postscript.FormatType != 0x00030000L ) flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif /* fixed width font? */ if ( face->postscript.isFixedPitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* vertical information? */ if ( face->vertical_info ) flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ if ( TT_FACE_HAS_KERNING( face ) ) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && tt_face_lookup_table( face, TTAG_fvar ) != 0 && tt_face_lookup_table( face, TTAG_gvar ) != 0 ) flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; /*********************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) { /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ /* indicates an oblique font face. This flag has been */ /* introduced in version 1.5 of the OpenType specification. */ if ( face->os2.fsSelection & 512 ) /* bit 9 */ flags |= FT_STYLE_FLAG_ITALIC; else if ( face->os2.fsSelection & 1 ) /* bit 0 */ flags |= FT_STYLE_FLAG_ITALIC; if ( face->os2.fsSelection & 32 ) /* bit 5 */ flags |= FT_STYLE_FLAG_BOLD; } else { /* this is an old Mac font, use the header field */ if ( face->header.Mac_Style & 1 ) flags |= FT_STYLE_FLAG_BOLD; if ( face->header.Mac_Style & 2 ) flags |= FT_STYLE_FLAG_ITALIC; } root->style_flags = flags; /*********************************************************************/ /* */ /* Polish the charmaps. */ /* */ /* Try to set the charmap encoding according to the platform & */ /* encoding ID of each charmap. */ /* */ tt_face_build_cmaps( face ); /* ignore errors */ /* set the encoding fields */ { FT_Int m; for ( m = 0; m < root->num_charmaps; m++ ) { FT_CharMap charmap = root->charmaps[m]; charmap->encoding = sfnt_find_encoding( charmap->platform_id, charmap->encoding_id ); #if 0 if ( root->charmap == NULL && charmap->encoding == FT_ENCODING_UNICODE ) { /* set 'root->charmap' to the first Unicode encoding we find */ root->charmap = charmap; } #endif } } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* * Now allocate the root array of FT_Bitmap_Size records and * populate them. Unfortunately, it isn't possible to indicate bit * depths in the FT_Bitmap_Size record. This is a design error. */ { FT_UInt i, count; count = face->sbit_num_strikes; if ( count > 0 ) { FT_Memory memory = face->root.stream->memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; if ( em_size == 0 || face->os2.version == 0xFFFFU ) { avgwidth = 0; em_size = 1; } if ( FT_NEW_ARRAY( root->available_sizes, count ) ) goto Exit; for ( i = 0; i < count; i++ ) { FT_Bitmap_Size* bsize = root->available_sizes + i; error = sfnt->load_strike_metrics( face, i, &metrics ); if ( error ) goto Exit; bsize->height = (FT_Short)( metrics.height >> 6 ); bsize->width = (FT_Short)( ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); bsize->x_ppem = metrics.x_ppem << 6; bsize->y_ppem = metrics.y_ppem << 6; /* assume 72dpi */ bsize->size = metrics.y_ppem << 6; } root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; root->num_fixed_sizes = (FT_Int)count; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* a font with no bitmaps and no outlines is scalable; */ /* it has only empty glyphs then */ if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) root->face_flags |= FT_FACE_FLAG_SCALABLE; /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if ( FT_IS_SCALABLE( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ root->bbox.xMin = face->header.xMin; root->bbox.yMin = face->header.yMin; root->bbox.xMax = face->header.xMax; root->bbox.yMax = face->header.yMax; root->units_per_EM = face->header.Units_Per_EM; /* XXX: Computing the ascender/descender/height is very different */ /* from what the specification tells you. Apparently, we */ /* must be careful because */ /* */ /* - not all fonts have an OS/2 table; in this case, we take */ /* the values in the horizontal header. However, these */ /* values very often are not reliable. */ /* */ /* - otherwise, the correct typographic values are in the */ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ /* */ /* However, certain fonts have these fields set to 0. */ /* Rather, they have usWinAscent & usWinDescent correctly */ /* set (but with different values). */ /* */ /* As an example, Arial Narrow is implemented through four */ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ /* */ /* Strangely, all fonts have the same values in their */ /* sTypoXXX fields, except ARIALNB which sets them to 0. */ /* */ /* On the other hand, they all have different */ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ /* table cannot be used to compute the text height reliably! */ /* */ /* The ascender and descender are taken from the `hhea' table. */ /* If zero, they are taken from the `OS/2' table. */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)( root->ascender - root->descender + face->horizontal.Line_Gap ); if ( !( root->ascender || root->descender ) ) { if ( face->os2.version != 0xFFFFU ) { if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) { root->ascender = face->os2.sTypoAscender; root->descender = face->os2.sTypoDescender; root->height = (FT_Short)( root->ascender - root->descender + face->os2.sTypoLineGap ); } else { root->ascender = (FT_Short)face->os2.usWinAscent; root->descender = -(FT_Short)face->os2.usWinDescent; root->height = (FT_UShort)( root->ascender - root->descender ); } } } root->max_advance_width = face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max : root->height ); /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ /* Adjust underline position from top edge to centre of */ /* stroke to convert TrueType meaning to FreeType meaning. */ root->underline_position = face->postscript.underlinePosition - face->postscript.underlineThickness / 2; root->underline_thickness = face->postscript.underlineThickness; } }
/* synthesized into a TTC with one offset table. */ static FT_Error sfnt_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error; FT_ULong tag, offset; static const FT_Frame_Field ttc_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TTC_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_LONG( version ), FT_FRAME_LONG( count ), /* this is ULong in the specs */ FT_FRAME_END }; face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; if ( tag != 0x00010000UL && tag != TTAG_ttcf && tag != TTAG_OTTO && tag != TTAG_true && tag != TTAG_typ1 && tag != 0x00020000UL ) { FT_TRACE2(( " not a font using the SFNT container format\n" )); return FT_THROW( Unknown_File_Format ); } face->ttc_header.tag = TTAG_ttcf; if ( tag == TTAG_ttcf ) { FT_Int n; FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) return error; if ( face->ttc_header.count == 0 ) return FT_THROW( Invalid_Table ); /* a rough size estimate: let's conservatively assume that there */ /* is just a single table info in each subfont header (12 + 16*1 = */ /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ /* size of the TTC header plus `28*count' bytes for all subfont */ /* headers */ if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) return error; for ( n = 0; n < face->ttc_header.count; n++ ) face->ttc_header.offsets[n] = FT_GET_ULONG(); FT_FRAME_EXIT(); } else { FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; if ( FT_NEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; } return error; }
sfnt_load_face( FT_Stream stream, TT_Face face, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { FT_Error error, psnames_error; FT_Bool has_outline; FT_Bool is_apple_sbit; SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_UNUSED( face_index ); FT_UNUSED( num_params ); FT_UNUSED( params ); /* Load tables */ /* We now support two SFNT-based bitmapped font formats. They */ /* are recognized easily as they do not include a `glyf' */ /* table. */ /* */ /* The first format comes from Apple, and uses a table named */ /* `bhed' instead of `head' to store the font header (using */ /* the same format). It also doesn't include horizontal and */ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ /* missing). */ /* */ /* The other format comes from Microsoft, and is used with */ /* WinCE/PocketPC. It looks like a standard TTF, except that */ /* it doesn't contain outlines. */ /* */ FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #else has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || tt_face_lookup_table( face, TTAG_CFF ) != 0 ); #endif is_apple_sbit = 0; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ if ( !has_outline && sfnt->load_bhed ) { LOAD_( bhed ); is_apple_sbit = FT_BOOL( !error ); } /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { LOAD_( head ); if ( error ) goto Exit; } if ( face->header.Units_Per_EM == 0 ) { error = SFNT_Err_Invalid_Table; goto Exit; } /* the following tables are often not present in embedded TrueType */ /* fonts within PDF documents, so don't check for them. */ LOAD_( maxp ); LOAD_( cmap ); /* the following tables are optional in PCL fonts -- */ /* don't check for errors */ LOAD_( name ); LOAD_( post ); psnames_error = error; /* do not load the metrics headers and tables if this is an Apple */ /* sbit font file */ if ( !is_apple_sbit ) { /* load the `hhea' and `hmtx' tables */ LOADM_( hhea, 0 ); if ( !error ) { LOADM_( hmtx, 0 ); if ( error == SFNT_Err_Table_Missing ) { error = SFNT_Err_Hmtx_Table_Missing; #ifdef FT_CONFIG_OPTION_INCREMENTAL /* If this is an incrementally loaded font and there are */ /* overriding metrics, tolerate a missing `hmtx' table. */ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs-> get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; error = SFNT_Err_Ok; } #endif } } else if ( error == SFNT_Err_Table_Missing ) { /* No `hhea' table necessary for SFNT Mac fonts. */ if ( face->format_tag == TTAG_true ) { FT_TRACE2(( "This is an SFNT Mac font.\n" )); has_outline = 0; error = SFNT_Err_Ok; } else error = SFNT_Err_Horiz_Header_Missing; } if ( error ) goto Exit; /* try to load the `vhea' and `vmtx' tables */ LOADM_( hhea, 1 ); if ( !error ) { LOADM_( hmtx, 1 ); if ( !error ) face->vertical_info = 1; } if ( error && error != SFNT_Err_Table_Missing ) goto Exit; LOAD_( os2 ); if ( error ) { if ( error != SFNT_Err_Table_Missing ) goto Exit; face->os2.version = 0xFFFFU; } } /* the optional tables */ /* embedded bitmap support. */ if ( sfnt->load_eblc ) { LOAD_( eblc ); if ( error ) { /* return an error if this font file has no outlines */ if ( error == SFNT_Err_Table_Missing && has_outline ) error = SFNT_Err_Ok; else goto Exit; } } LOAD_( pclt ); if ( error ) { if ( error != SFNT_Err_Table_Missing ) goto Exit; face->pclt.Version = 0; } /* consider the kerning and gasp tables as optional */ LOAD_( gasp ); LOAD_( kern ); error = SFNT_Err_Ok; face->root.num_glyphs = face->max_profile.numGlyphs; face->root.family_name = tt_face_get_name( face, TT_NAME_ID_PREFERRED_FAMILY ); if ( !face->root.family_name ) face->root.family_name = tt_face_get_name( face, TT_NAME_ID_FONT_FAMILY ); face->root.style_name = tt_face_get_name( face, TT_NAME_ID_PREFERRED_SUBFAMILY ); if ( !face->root.style_name ) face->root.style_name = tt_face_get_name( face, TT_NAME_ID_FONT_SUBFAMILY ); /* now set up root fields */ { FT_Face root = &face->root; FT_Int32 flags = root->face_flags; /*********************************************************************/ /* */ /* Compute face flags. */ /* */ if ( has_outline == TRUE ) flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES if ( psnames_error == SFNT_Err_Ok && face->postscript.FormatType != 0x00030000L ) flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif /* fixed width font? */ if ( face->postscript.isFixedPitch ) flags |= FT_FACE_FLAG_FIXED_WIDTH; /* vertical information? */ if ( face->vertical_info ) flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ if ( TT_FACE_HAS_KERNING( face ) ) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && tt_face_lookup_table( face, TTAG_fvar ) != 0 && tt_face_lookup_table( face, TTAG_gvar ) != 0 ) flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; /*********************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) { /* we have an OS/2 table; use the `fsSelection' field */ if ( face->os2.fsSelection & 1 ) flags |= FT_STYLE_FLAG_ITALIC; if ( face->os2.fsSelection & 32 ) flags |= FT_STYLE_FLAG_BOLD; } else { /* this is an old Mac font, use the header field */ if ( face->header.Mac_Style & 1 ) flags |= FT_STYLE_FLAG_BOLD; if ( face->header.Mac_Style & 2 ) flags |= FT_STYLE_FLAG_ITALIC; } root->style_flags = flags; /*********************************************************************/ /* */ /* Polish the charmaps. */ /* */ /* Try to set the charmap encoding according to the platform & */ /* encoding ID of each charmap. */ /* */ tt_face_build_cmaps( face ); /* ignore errors */ /* set the encoding fields */ { FT_Int m; for ( m = 0; m < root->num_charmaps; m++ ) { FT_CharMap charmap = root->charmaps[m]; charmap->encoding = sfnt_find_encoding( charmap->platform_id, charmap->encoding_id ); #if 0 if ( root->charmap == NULL && charmap->encoding == FT_ENCODING_UNICODE ) { /* set 'root->charmap' to the first Unicode encoding we find */ root->charmap = charmap; } #endif } } /*********************************************************************/ /* */ /* Set up metrics. */ /* */ if ( has_outline == TRUE ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ root->bbox.xMin = face->header.xMin; root->bbox.yMin = face->header.yMin; root->bbox.xMax = face->header.xMax; root->bbox.yMax = face->header.yMax; root->units_per_EM = face->header.Units_Per_EM; /* XXX: Computing the ascender/descender/height is very different */ /* from what the specification tells you. Apparently, we */ /* must be careful because */ /* */ /* - not all fonts have an OS/2 table; in this case, we take */ /* the values in the horizontal header. However, these */ /* values very often are not reliable. */ /* */ /* - otherwise, the correct typographic values are in the */ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ /* */ /* However, certains fonts have these fields set to 0. */ /* Rather, they have usWinAscent & usWinDescent correctly */ /* set (but with different values). */ /* */ /* As an example, Arial Narrow is implemented through four */ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ /* */ /* Strangely, all fonts have the same values in their */ /* sTypoXXX fields, except ARIALNB which sets them to 0. */ /* */ /* On the other hand, they all have different */ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ /* table cannot be used to compute the text height reliably! */ /* */ /* The ascender/descender/height are computed from the OS/2 table */ /* when found. Otherwise, they're taken from the horizontal */ /* header. */ /* */ root->ascender = face->horizontal.Ascender; root->descender = face->horizontal.Descender; root->height = (FT_Short)( root->ascender - root->descender + face->horizontal.Line_Gap ); #if 0 /* if the line_gap is 0, we add an extra 15% to the text height -- */ /* this computation is based on various versions of Times New Roman */ if ( face->horizontal.Line_Gap == 0 ) root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 ); #endif //#if 0 - This line commented out by Chris Cooper - Symbian /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */ // if ( face->os2.version != 0xFFFF && root->ascender ) - Symbian change if (( face->os2.version != 0xFFFF && root->ascender ) && (face->os2.sTypoAscender - face->os2.sTypoDescender)) { FT_Int height; root->ascender = face->os2.sTypoAscender; root->descender = (FT_Short)(-face->os2.sTypoDescender); height = root->ascender + root->descender + face->os2.sTypoLineGap; /* if the line_gap is 0, we add an extra 15% to the text height -- */ /* this computation is based on various versions of Times New Roman */ if ( face->os2.sTypoLineGap == 0 ) // Added by Symbian height = ( height * 115 + 50 ) / 100; // Added by Symbian if ( height > root->height ) root->height = (FT_Short)height; } //#endif /* 0 */ - Symbian change root->max_advance_width = face->horizontal.advance_Width_Max; root->max_advance_height = (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max : root->height ); root->underline_position = face->postscript.underlinePosition; root->underline_thickness = face->postscript.underlineThickness; } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* * Now allocate the root array of FT_Bitmap_Size records and * populate them. Unfortunately, it isn't possible to indicate bit * depths in the FT_Bitmap_Size record. This is a design error. */ { FT_UInt i, count; #if defined FT_OPTIMIZE_MEMORY && !defined FT_CONFIG_OPTION_OLD_INTERNALS count = face->sbit_num_strikes; #else count = (FT_UInt)face->num_sbit_strikes; #endif if ( count > 0 ) { FT_Memory memory = face->root.stream->memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; if ( em_size == 0 || face->os2.version == 0xFFFFU ) { avgwidth = 0; em_size = 1; } if ( FT_NEW_ARRAY( root->available_sizes, count ) ) goto Exit; for ( i = 0; i < count; i++ ) { FT_Bitmap_Size* bsize = root->available_sizes + i; error = sfnt->load_strike_metrics( face, i, &metrics ); if ( error ) goto Exit; bsize->height = (FT_Short)( metrics.height >> 6 ); bsize->width = (FT_Short)( ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); bsize->x_ppem = metrics.x_ppem << 6; bsize->y_ppem = metrics.y_ppem << 6; /* assume 72dpi */ bsize->size = metrics.y_ppem << 6; } root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; root->num_fixed_sizes = (FT_Int)count; } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ }
pfr_face_init( FT_Stream stream, FT_Face pfrface, FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { PFR_Face face = (PFR_Face)pfrface; FT_Error error; FT_UNUSED( num_params ); FT_UNUSED( params ); FT_TRACE2(( "PFR driver\n" )); /* load the header and check it */ error = pfr_header_load( &face->header, stream ); if ( error ) goto Exit; if ( !pfr_header_check( &face->header ) ) { FT_TRACE2(( " not a PFR font\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } /* check face index */ { FT_UInt num_faces; error = pfr_log_font_count( stream, face->header.log_dir_offset, &num_faces ); if ( error ) goto Exit; pfrface->num_faces = num_faces; } if ( face_index < 0 ) goto Exit; if ( face_index >= pfrface->num_faces ) { FT_ERROR(( "pfr_face_init: invalid face index\n" )); error = FT_THROW( Invalid_Argument ); goto Exit; } /* load the face */ error = pfr_log_font_load( &face->log_font, stream, face_index, face->header.log_dir_offset, FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); if ( error ) goto Exit; /* now load the physical font descriptor */ error = pfr_phy_font_load( &face->phy_font, stream, face->log_font.phys_offset, face->log_font.phys_size ); if ( error ) goto Exit; /* now set up all root face fields */ { PFR_PhyFont phy_font = &face->phy_font; pfrface->face_index = face_index; pfrface->num_glyphs = phy_font->num_chars + 1; pfrface->face_flags = FT_FACE_FLAG_SCALABLE; /* if all characters point to the same gps_offset 0, we */ /* assume that the font only contains bitmaps */ { FT_UInt nn; for ( nn = 0; nn < phy_font->num_chars; nn++ ) if ( phy_font->chars[nn].gps_offset != 0 ) break; if ( nn == phy_font->num_chars ) { if ( phy_font->num_strikes > 0 ) pfrface->face_flags = 0; /* not scalable */ else { FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } } } if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 ) pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; if ( phy_font->flags & PFR_PHY_VERTICAL ) pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; else pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; if ( phy_font->num_strikes > 0 ) pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; if ( phy_font->num_kern_pairs > 0 ) pfrface->face_flags |= FT_FACE_FLAG_KERNING; /* If no family name was found in the "undocumented" auxiliary * data, use the font ID instead. This sucks but is better than * nothing. */ pfrface->family_name = phy_font->family_name; if ( pfrface->family_name == NULL ) pfrface->family_name = phy_font->font_id; /* note that the style name can be NULL in certain PFR fonts, * probably meaning "Regular" */ pfrface->style_name = phy_font->style_name; pfrface->num_fixed_sizes = 0; pfrface->available_sizes = 0; pfrface->bbox = phy_font->bbox; pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; pfrface->ascender = (FT_Short) phy_font->bbox.yMax; pfrface->descender = (FT_Short) phy_font->bbox.yMin; pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); if ( pfrface->height < pfrface->ascender - pfrface->descender ) pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender); if ( phy_font->num_strikes > 0 ) { FT_UInt n, count = phy_font->num_strikes; FT_Bitmap_Size* size; PFR_Strike strike; FT_Memory memory = pfrface->stream->memory; if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) goto Exit; size = pfrface->available_sizes; strike = phy_font->strikes; for ( n = 0; n < count; n++, size++, strike++ ) { size->height = (FT_UShort)strike->y_ppm; size->width = (FT_UShort)strike->x_ppm; size->size = strike->y_ppm << 6; size->x_ppem = strike->x_ppm << 6; size->y_ppem = strike->y_ppm << 6; } pfrface->num_fixed_sizes = count; } /* now compute maximum advance width */ if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; else { FT_Int max = 0; FT_UInt count = phy_font->num_chars; PFR_Char gchar = phy_font->chars; for ( ; count > 0; count--, gchar++ ) { if ( max < gchar->advance ) max = gchar->advance; } pfrface->max_advance_width = (FT_Short)max; } pfrface->max_advance_height = pfrface->height; pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); /* create charmap */ { FT_CharMapRec charmap; charmap.face = pfrface; charmap.platform_id = TT_PLATFORM_MICROSOFT; charmap.encoding_id = TT_MS_ID_UNICODE_CS; charmap.encoding = FT_ENCODING_UNICODE; error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); #if 0 /* Select default charmap */ if ( pfrface->num_charmaps ) pfrface->charmap = pfrface->charmaps[0]; #endif } /* check whether we've loaded any kerning pairs */ if ( phy_font->num_kern_pairs ) pfrface->face_flags |= FT_FACE_FLAG_KERNING; } Exit: return error; }
pfr_phy_font_load( PFR_PhyFont phy_font, FT_Stream stream, FT_UInt32 offset, FT_UInt32 size ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt flags; FT_ULong num_aux; FT_Byte* p; FT_Byte* limit; phy_font->memory = memory; phy_font->offset = offset; phy_font->kern_items = NULL; phy_font->kern_items_tail = &phy_font->kern_items; if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) goto Exit; phy_font->cursor = stream->cursor; p = stream->cursor; limit = p + size; PFR_CHECK( 15 ); phy_font->font_ref_number = PFR_NEXT_USHORT( p ); phy_font->outline_resolution = PFR_NEXT_USHORT( p ); phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); phy_font->flags = flags = PFR_NEXT_BYTE( p ); /* get the standard advance for non-proportional fonts */ if ( !(flags & PFR_PHY_PROPORTIONAL) ) { PFR_CHECK( 2 ); phy_font->standard_advance = PFR_NEXT_SHORT( p ); } /* load the extra items when present */ if ( flags & PFR_PHY_EXTRA_ITEMS ) { error = pfr_extra_items_parse( &p, limit, pfr_phy_font_extra_items, phy_font ); if ( error ) goto Fail; } /* In certain fonts, the auxiliary bytes contain interesting */ /* information. These are not in the specification but can be */ /* guessed by looking at the content of a few PFR0 fonts. */ PFR_CHECK( 3 ); num_aux = PFR_NEXT_ULONG( p ); if ( num_aux > 0 ) { FT_Byte* q = p; FT_Byte* q2; PFR_CHECK( num_aux ); p += num_aux; while ( num_aux > 0 ) { FT_UInt length, type; if ( q + 4 > p ) break; length = PFR_NEXT_USHORT( q ); if ( length < 4 || length > num_aux ) break; q2 = q + length - 2; type = PFR_NEXT_USHORT( q ); switch ( type ) { case 1: /* this seems to correspond to the font's family name, * padded to 16-bits with one zero when necessary */ error = pfr_aux_name_load( q, length - 4U, memory, &phy_font->family_name ); if ( error ) goto Exit; break; case 2: if ( q + 32 > q2 ) break; q += 10; phy_font->ascent = PFR_NEXT_SHORT( q ); phy_font->descent = PFR_NEXT_SHORT( q ); phy_font->leading = PFR_NEXT_SHORT( q ); break; case 3: /* this seems to correspond to the font's style name, * padded to 16-bits with one zero when necessary */ error = pfr_aux_name_load( q, length - 4U, memory, &phy_font->style_name ); if ( error ) goto Exit; break; default: ; } q = q2; num_aux -= length; } } /* read the blue values */ { FT_UInt n, count; PFR_CHECK( 1 ); phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); PFR_CHECK( count * 2 ); if ( FT_NEW_ARRAY( phy_font->blue_values, count ) ) goto Fail; for ( n = 0; n < count; n++ ) phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); } PFR_CHECK( 8 ); phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); phy_font->blue_scale = PFR_NEXT_BYTE( p ); phy_font->vertical.standard = PFR_NEXT_USHORT( p ); phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); /* read the character descriptors */ { FT_UInt n, count, Size; phy_font->num_chars = count = PFR_NEXT_USHORT( p ); phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor ); if ( FT_NEW_ARRAY( phy_font->chars, count ) ) goto Fail; Size = 1 + 1 + 2; if ( flags & PFR_PHY_2BYTE_CHARCODE ) Size += 1; if ( flags & PFR_PHY_PROPORTIONAL ) Size += 2; if ( flags & PFR_PHY_ASCII_CODE ) Size += 1; if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) Size += 1; if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) Size += 1; PFR_CHECK( count * Size ); for ( n = 0; n < count; n++ ) { PFR_Char cur = &phy_font->chars[n]; cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) ? PFR_NEXT_USHORT( p ) : PFR_NEXT_BYTE( p ); cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) ? PFR_NEXT_SHORT( p ) : phy_font->standard_advance; #if 0 cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) ? PFR_NEXT_BYTE( p ) : 0; #else if ( flags & PFR_PHY_ASCII_CODE ) p += 1; #endif cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) ? PFR_NEXT_USHORT( p ) : PFR_NEXT_BYTE( p ); cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) ? PFR_NEXT_ULONG( p ) : PFR_NEXT_USHORT( p ); } } /* that's it! */ Fail: FT_FRAME_EXIT(); /* save position of bitmap info */ phy_font->bct_offset = FT_STREAM_POS(); phy_font->cursor = NULL; Exit: return error; Too_Short: error = FT_THROW( Invalid_Table ); FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); goto Fail; }
static FT_Error pcf_get_properties( FT_Stream stream, PCF_Face face ) { PCF_ParseProperty props = 0; PCF_Property properties = 0; FT_Int nprops, i; FT_ULong format, size; FT_Error error; FT_Memory memory = FT_FACE(face)->memory; FT_ULong string_size; FT_String* strings = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_PROPERTIES, &format, &size ); if ( error ) goto Bail; if ( FT_READ_ULONG_LE( format ) ) goto Bail; FT_TRACE4(( "get_prop: format = %ld\n", format )); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) goto Bail; if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nprops ); else (void)FT_READ_ULONG_LE( nprops ); if ( error ) goto Bail; FT_TRACE4(( "get_prop: nprop = %d\n", nprops )); if ( FT_NEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) goto Bail; } else { if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) goto Bail; } } /* pad the property array */ /* */ /* clever here - nprops is the same as the number of odd-units read, */ /* as only isStringProp are odd length (Keith Packard) */ /* */ if ( nprops & 3 ) { i = 4 - ( nprops & 3 ); FT_Stream_Skip( stream, i ); } if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( string_size ); else (void)FT_READ_ULONG_LE( string_size ); if ( error ) goto Bail; FT_TRACE4(( "get_prop: string_size = %ld\n", string_size )); if ( FT_NEW_ARRAY( strings, string_size ) ) goto Bail; error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); if ( error ) goto Bail; if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { /* XXX: make atom */ if ( FT_NEW_ARRAY( properties[i].name, ft_strlen( strings + props[i].name ) + 1 ) ) goto Bail; ft_strcpy( properties[i].name,strings + props[i].name ); properties[i].isString = props[i].isString; if ( props[i].isString ) { if ( FT_NEW_ARRAY( properties[i].value.atom, ft_strlen( strings + props[i].value ) + 1 ) ) goto Bail; ft_strcpy( properties[i].value.atom, strings + props[i].value ); } else properties[i].value.integer = props[i].value; } face->properties = properties; face->nprops = nprops; FT_FREE( props ); FT_FREE( strings ); return PCF_Err_Ok; Bail: FT_FREE( props ); FT_FREE( strings ); return error; }
static FT_Error pcf_get_encodings( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format, size; int firstCol, lastCol; int firstRow, lastRow; int nencoding, encodingOffset; int i, j; PCF_Encoding tmpEncoding = NULL, encoding = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BDF_ENCODINGS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 14 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { firstCol = FT_GET_SHORT(); lastCol = FT_GET_SHORT(); firstRow = FT_GET_SHORT(); lastRow = FT_GET_SHORT(); face->defaultChar = FT_GET_SHORT(); } else { firstCol = FT_GET_SHORT_LE(); lastCol = FT_GET_SHORT_LE(); firstRow = FT_GET_SHORT_LE(); lastRow = FT_GET_SHORT_LE(); face->defaultChar = FT_GET_SHORT_LE(); } FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return PCF_Err_Invalid_File_Format; FT_TRACE4(( "pdf_get_encodings:\n" )); FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", firstCol, lastCol, firstRow, lastRow )); nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) return PCF_Err_Out_Of_Memory; error = FT_Stream_EnterFrame( stream, 2 * nencoding ); if ( error ) goto Bail; for ( i = 0, j = 0 ; i < nencoding; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) encodingOffset = FT_GET_SHORT(); else encodingOffset = FT_GET_SHORT_LE(); if ( encodingOffset != -1 ) { tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + firstRow ) * 256 ) + ( ( i % ( lastCol - firstCol + 1 ) ) + firstCol ); tmpEncoding[j].glyph = (FT_Short)encodingOffset; FT_TRACE5(( " code %d (0x%04X): idx %d\n", tmpEncoding[j].enc, tmpEncoding[j].enc, tmpEncoding[j].glyph )); j++; } } FT_Stream_ExitFrame( stream ); if ( FT_NEW_ARRAY( encoding, j ) ) goto Bail; for ( i = 0; i < j; i++ ) { encoding[i].enc = tmpEncoding[i].enc; encoding[i].glyph = tmpEncoding[i].glyph; } face->nencodings = j; face->encodings = encoding; FT_FREE( tmpEncoding ); return error; Bail: FT_FREE( encoding ); FT_FREE( tmpEncoding ); return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format = 0; FT_ULong size = 0; PCF_Metric metrics = 0; int i; int nmetrics = -1; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; error = FT_READ_ULONG_LE( format ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return PCF_Err_Invalid_File_Format; if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error || nmetrics == -1 ) return PCF_Err_Invalid_File_Format; face->nmetrics = nmetrics; if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return PCF_Err_Out_Of_Memory; metrics = face->metrics; for ( i = 0; i < nmetrics; i++ ) { pcf_get_metric( stream, format, metrics + i ); metrics[i].bits = 0; FT_TRACE4(( "%d : width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, ( metrics + i )->characterWidth, ( metrics + i )->leftSideBearing, ( metrics + i )->rightSideBearing, ( metrics + i )->ascent, ( metrics + i )->descent, ( metrics + i )->attributes )); if ( error ) break; } if ( error ) FT_FREE( face->metrics ); return error; }
static FT_Error pcf_get_properties( FT_Stream stream, PCF_Face face ) { PCF_ParseProperty props = 0; PCF_Property properties = NULL; FT_ULong nprops, i; FT_ULong format, size; FT_Error error; FT_Memory memory = FT_FACE( face )->memory; FT_ULong string_size; FT_String* strings = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_PROPERTIES, &format, &size ); if ( error ) goto Bail; if ( FT_READ_ULONG_LE( format ) ) goto Bail; FT_TRACE4(( "pcf_get_properties:\n" )); FT_TRACE4(( " format = %ld\n", format )); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) goto Bail; if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nprops ); else (void)FT_READ_ULONG_LE( nprops ); if ( error ) goto Bail; FT_TRACE4(( " nprop = %d (truncate %d props)\n", (int)nprops, nprops - (int)nprops )); nprops = (int)nprops; /* rough estimate */ if ( nprops > size / PCF_PROPERTY_SIZE ) { error = FT_THROW( Invalid_Table ); goto Bail; } face->nprops = (int)nprops; if ( FT_NEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) goto Bail; } else { if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) goto Bail; } } /* pad the property array */ /* */ /* clever here - nprops is the same as the number of odd-units read, */ /* as only isStringProp are odd length (Keith Packard) */ /* */ if ( nprops & 3 ) { i = 4 - ( nprops & 3 ); if ( FT_STREAM_SKIP( i ) ) { error = FT_THROW( Invalid_Stream_Skip ); goto Bail; } } if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( string_size ); else (void)FT_READ_ULONG_LE( string_size ); if ( error ) goto Bail; FT_TRACE4(( " string_size = %ld\n", string_size )); /* rough estimate */ if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) { error = FT_THROW( Invalid_Table ); goto Bail; } /* allocate one more byte so that we have a final null byte */ if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) goto Bail; error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); if ( error ) goto Bail; if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; face->properties = properties; for ( i = 0; i < nprops; i++ ) { FT_Long name_offset = props[i].name; if ( ( name_offset < 0 ) || ( (FT_ULong)name_offset > string_size ) ) { error = FT_THROW( Invalid_Offset ); goto Bail; } if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) goto Bail; FT_TRACE4(( " %s:", properties[i].name )); properties[i].isString = props[i].isString; if ( props[i].isString ) { FT_Long value_offset = props[i].value; if ( ( value_offset < 0 ) || ( (FT_ULong)value_offset > string_size ) ) { error = FT_THROW( Invalid_Offset ); goto Bail; } if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) goto Bail; FT_TRACE4(( " `%s'\n", properties[i].value.atom )); } else { properties[i].value.l = props[i].value; FT_TRACE4(( " %d\n", properties[i].value.l )); } } error = FT_Err_Ok; Bail: FT_FREE( props ); FT_FREE( strings ); return error; }
static FT_Error pcf_get_bitmaps( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_Long* offsets; FT_Long bitmapSizes[GLYPHPADOPTIONS]; FT_ULong format, size; int nbitmaps, i, sizebitmaps = 0; char* bitmaps; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BITMAPS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 8 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) nbitmaps = FT_GET_ULONG(); else nbitmaps = FT_GET_ULONG_LE(); FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return PCF_Err_Invalid_File_Format; if ( nbitmaps != face->nmetrics ) return PCF_Err_Invalid_File_Format; if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) return error; for ( i = 0; i < nbitmaps; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( offsets[i] ); else (void)FT_READ_LONG_LE( offsets[i] ); FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] )); } if ( error ) goto Bail; for ( i = 0; i < GLYPHPADOPTIONS; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( bitmapSizes[i] ); else (void)FT_READ_LONG_LE( bitmapSizes[i] ); if ( error ) goto Bail; sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] )); } FT_TRACE4(( " %d bitmaps, padding index %ld\n", nbitmaps, PCF_GLYPH_PAD_INDEX( format ) )); FT_TRACE4(( "bitmap size = %d\n", sizebitmaps )); FT_UNUSED( sizebitmaps ); /* only used for debugging */ for ( i = 0; i < nbitmaps; i++ ) face->metrics[i].bits = stream->pos + offsets[i]; face->bitmapsFormat = format; FT_FREE ( offsets ); return error; Bail: FT_FREE ( offsets ); FT_FREE ( bitmaps ); return error; }
static FT_Error pcf_get_bitmaps( FT_Stream stream, PCF_Face face ) { FT_Error error; FT_Memory memory = FT_FACE( face )->memory; FT_Long* offsets = NULL; FT_Long bitmapSizes[GLYPHPADOPTIONS]; FT_ULong format, size; FT_ULong nbitmaps, i, sizebitmaps = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BITMAPS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 8 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) nbitmaps = FT_GET_ULONG(); else nbitmaps = FT_GET_ULONG_LE(); FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return FT_THROW( Invalid_File_Format ); FT_TRACE4(( "pcf_get_bitmaps:\n" )); FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); /* XXX: PCF_Face->nmetrics is signed FT_Long, see pcf.h */ if ( face->nmetrics < 0 || nbitmaps != (FT_ULong)face->nmetrics ) return FT_THROW( Invalid_File_Format ); if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) return error; for ( i = 0; i < nbitmaps; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( offsets[i] ); else (void)FT_READ_LONG_LE( offsets[i] ); FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", i, offsets[i], offsets[i] )); } if ( error ) goto Bail; for ( i = 0; i < GLYPHPADOPTIONS; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( bitmapSizes[i] ); else (void)FT_READ_LONG_LE( bitmapSizes[i] ); if ( error ) goto Bail; sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); } FT_TRACE4(( " %d bitmaps, padding index %ld\n", nbitmaps, PCF_GLYPH_PAD_INDEX( format ) )); FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); FT_UNUSED( sizebitmaps ); /* only used for debugging */ for ( i = 0; i < nbitmaps; i++ ) { /* rough estimate */ if ( ( offsets[i] < 0 ) || ( (FT_ULong)offsets[i] > size ) ) { FT_TRACE0(( "pcf_get_bitmaps:" " invalid offset to bitmap data of glyph %d\n", i )); } else face->metrics[i].bits = stream->pos + offsets[i]; } face->bitmapsFormat = format; Bail: FT_FREE( offsets ); return error; }
pcf_load_font( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_Bool hasBDFAccelerators; error = pcf_read_TOC( stream, face ); if ( error ) goto Exit; error = pcf_get_properties( stream, face ); if ( error ) goto Exit; /* Use the old accelerators if no BDF accelerators are in the file. */ hasBDFAccelerators = pcf_has_table_type( face->toc.tables, face->toc.count, PCF_BDF_ACCELERATORS ); if ( !hasBDFAccelerators ) { error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); if ( error ) goto Exit; } /* metrics */ error = pcf_get_metrics( stream, face ); if ( error ) goto Exit; /* bitmaps */ error = pcf_get_bitmaps( stream, face ); if ( error ) goto Exit; /* encodings */ error = pcf_get_encodings( stream, face ); if ( error ) goto Exit; /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ if ( hasBDFAccelerators ) { error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); if ( error ) goto Exit; } /* XXX: TO DO: inkmetrics and glyph_names are missing */ /* now construct the face object */ { FT_Face root = FT_FACE( face ); PCF_Property prop; int size_set = 0; root->num_faces = 1; root->face_index = 0; root->face_flags = FT_FACE_FLAG_FIXED_SIZES | FT_FACE_FLAG_HORIZONTAL | FT_FACE_FLAG_FAST_GLYPHS; if ( face->accel.constantWidth ) root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; root->style_flags = 0; prop = pcf_find_property( face, "SLANT" ); if ( prop != NULL ) if ( prop->isString ) if ( ( *(prop->value.atom) == 'O' ) || ( *(prop->value.atom) == 'I' ) ) root->style_flags |= FT_STYLE_FLAG_ITALIC; prop = pcf_find_property( face, "WEIGHT_NAME" ); if ( prop != NULL ) if ( prop->isString ) if ( *(prop->value.atom) == 'B' ) root->style_flags |= FT_STYLE_FLAG_BOLD; root->style_name = (char *)"Regular"; if ( root->style_flags & FT_STYLE_FLAG_BOLD ) { if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) root->style_name = (char *)"Bold Italic"; else root->style_name = (char *)"Bold"; } else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) root->style_name = (char *)"Italic"; prop = pcf_find_property( face, "FAMILY_NAME" ); if ( prop != NULL ) { if ( prop->isString ) { int l = ft_strlen( prop->value.atom ) + 1; if ( FT_NEW_ARRAY( root->family_name, l ) ) goto Exit; ft_strcpy( root->family_name, prop->value.atom ); } } else root->family_name = 0; root->num_glyphs = face->nmetrics; root->num_fixed_sizes = 1; if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) goto Exit; prop = pcf_find_property( face, "PIXEL_SIZE" ); if ( prop != NULL ) { root->available_sizes->height = root->available_sizes->width = (FT_Short)( prop->value.integer ); size_set = 1; } else { prop = pcf_find_property( face, "POINT_SIZE" ); if ( prop != NULL ) { PCF_Property xres, yres, avgw; xres = pcf_find_property( face, "RESOLUTION_X" ); yres = pcf_find_property( face, "RESOLUTION_Y" ); avgw = pcf_find_property( face, "AVERAGE_WIDTH" ); if ( ( yres != NULL ) && ( xres != NULL ) ) { root->available_sizes->height = (FT_Short)( prop->value.integer * yres->value.integer / 720 ); root->available_sizes->width = (FT_Short)( prop->value.integer * xres->value.integer / 720 ); size_set = 1; } } } if (size_set == 0 ) { root->available_sizes->width = 12; root->available_sizes->height = 12; } /* set-up charset */ { PCF_Property charset_registry = 0, charset_encoding = 0; charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); if ( ( charset_registry != NULL ) && ( charset_encoding != NULL ) ) { if ( ( charset_registry->isString ) && ( charset_encoding->isString ) ) { if ( FT_NEW_ARRAY( face->charset_encoding, ft_strlen( charset_encoding->value.atom ) + 1 ) ) goto Exit; if ( FT_NEW_ARRAY( face->charset_registry, ft_strlen( charset_registry->value.atom ) + 1 ) ) goto Exit; ft_strcpy( face->charset_registry, charset_registry->value.atom ); ft_strcpy( face->charset_encoding, charset_encoding->value.atom ); } } } } Exit: if ( error ) { /* this is done to respect the behaviour of the original */ /* PCF font driver. */ error = PCF_Err_Invalid_File_Format; } return error; }
static FT_Error pcf_read_TOC( FT_Stream stream, PCF_Face face ) { FT_Error error; PCF_Toc toc = &face->toc; PCF_Table tables; FT_Memory memory = FT_FACE( face )->memory; FT_UInt n; FT_ULong size; if ( FT_STREAM_SEEK( 0 ) || FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) ) return FT_THROW( Cannot_Open_Resource ); if ( toc->version != PCF_FILE_VERSION || toc->count > FT_ARRAY_MAX( face->toc.tables ) || toc->count == 0 ) return FT_THROW( Invalid_File_Format ); if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) return FT_THROW( Out_Of_Memory ); tables = face->toc.tables; for ( n = 0; n < toc->count; n++ ) { if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) goto Exit; tables++; } /* Sort tables and check for overlaps. Because they are almost */ /* always ordered already, an in-place bubble sort with simultaneous */ /* boundary checking seems appropriate. */ tables = face->toc.tables; for ( n = 0; n < toc->count - 1; n++ ) { FT_UInt i, have_change; have_change = 0; for ( i = 0; i < toc->count - 1 - n; i++ ) { PCF_TableRec tmp; if ( tables[i].offset > tables[i + 1].offset ) { tmp = tables[i]; tables[i] = tables[i + 1]; tables[i + 1] = tmp; have_change = 1; } if ( ( tables[i].size > tables[i + 1].offset ) || ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) { error = FT_THROW( Invalid_Offset ); goto Exit; } } if ( !have_change ) break; } /* * We now check whether the `size' and `offset' values are reasonable: * `offset' + `size' must not exceed the stream size. * * Note, however, that X11's `pcfWriteFont' routine (used by the * `bdftopcf' program to create PDF font files) has two special * features. * * - It always assigns the accelerator table a size of 100 bytes in the * TOC, regardless of its real size, which can vary between 34 and 72 * bytes. * * - Due to the way the routine is designed, it ships out the last font * table with its real size, ignoring the TOC's size value. Since * the TOC size values are always rounded up to a multiple of 4, the * difference can be up to three bytes for all tables except the * accelerator table, for which the difference can be as large as 66 * bytes. * */ tables = face->toc.tables; size = stream->size; for ( n = 0; n < toc->count - 1; n++ ) { /* we need two checks to avoid overflow */ if ( ( tables->size > size ) || ( tables->offset > size - tables->size ) ) { error = FT_THROW( Invalid_Table ); goto Exit; } tables++; } /* only check `tables->offset' for last table element ... */ if ( ( tables->offset > size ) ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* ... and adjust `tables->size' to the real value if necessary */ if ( tables->size > size - tables->offset ) tables->size = size - tables->offset; #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt i, j; const char* name = "?"; FT_TRACE4(( "pcf_read_TOC:\n" )); FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); tables = face->toc.tables; for ( i = 0; i < toc->count; i++ ) { for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ ) if ( tables[i].type == (FT_UInt)( 1 << j ) ) name = tableNames[j]; FT_TRACE4(( " %d: type=%s, format=0x%X, " "size=%ld (0x%lX), offset=%ld (0x%lX)\n", i, name, tables[i].format, tables[i].size, tables[i].size, tables[i].offset, tables[i].offset )); } } #endif return FT_Err_Ok; Exit: FT_FREE( face->toc.tables ); return error; }
static FT_Error pcf_read_TOC( FT_Stream stream, PCF_Face face ) { FT_Error error; PCF_Toc toc = &face->toc; PCF_Table tables; FT_Memory memory = FT_FACE(face)->memory; FT_UInt n; if ( FT_STREAM_SEEK ( 0 ) || FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) return PCF_Err_Cannot_Open_Resource; if ( toc->version != PCF_FILE_VERSION ) return PCF_Err_Invalid_File_Format; if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) return PCF_Err_Out_Of_Memory; tables = face->toc.tables; for ( n = 0; n < toc->count; n++ ) { if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) goto Exit; tables++; } #if defined( FT_DEBUG_LEVEL_TRACE ) { FT_UInt i, j; const char* name = "?"; FT_TRACE4(( "Tables count: %ld\n", face->toc.count )); tables = face->toc.tables; for ( i = 0; i < toc->count; i++ ) { for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ ) if ( tables[i].type == (FT_UInt)( 1 << j ) ) name = tableNames[j]; FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX " "size=0x%06lX (%8ld) offset=0x%04lX\n", i, name, tables[i].format, tables[i].size, tables[i].size, tables[i].offset )); } } #endif return PCF_Err_Ok; Exit: FT_FREE( face->toc.tables ); return error; }
tt_face_load_name( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; FT_UInt count; TT_NameTable table; static const FT_Frame_Field name_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameTableRec FT_FRAME_START( 6 ), FT_FRAME_USHORT( format ), FT_FRAME_USHORT( numNameRecords ), FT_FRAME_USHORT( storageOffset ), FT_FRAME_END }; static const FT_Frame_Field name_record_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_NameEntryRec /* no FT_FRAME_START */ FT_FRAME_USHORT( platformID ), FT_FRAME_USHORT( encodingID ), FT_FRAME_USHORT( languageID ), FT_FRAME_USHORT( nameID ), FT_FRAME_USHORT( stringLength ), FT_FRAME_USHORT( stringOffset ), FT_FRAME_END }; table = &face->name_table; table->stream = stream; error = face->goto_table( face, TTAG_name, stream, &table_len ); if ( error ) goto Exit; table_pos = FT_STREAM_POS(); if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) goto Exit; /* Some popular Asian fonts have an invalid `storageOffset' value */ /* (it should be at least "6 + 12*num_names"). However, the string */ /* offsets, computed as "storageOffset + entry->stringOffset", are */ /* valid pointers within the name table... */ /* */ /* We thus can't check `storageOffset' right now. */ /* */ storage_start = table_pos + 6 + 12*table->numNameRecords; storage_limit = table_pos + table_len; if ( storage_start > storage_limit ) { FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); error = SFNT_Err_Name_Table_Missing; goto Exit; } /* Allocate the array of name records. */ count = table->numNameRecords; table->numNameRecords = 0; if ( FT_NEW_ARRAY( table->names, count ) || FT_FRAME_ENTER( count * 12 ) ) goto Exit; /* Load the name records and determine how much storage is needed */ /* to hold the strings themselves. */ { TT_NameEntryRec* entry = table->names; for ( ; count > 0; count-- ) { if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) continue; /* check that the name is not empty */ if ( entry->stringLength == 0 ) continue; /* check that the name string is within the table */ entry->stringOffset += table_pos + table->storageOffset; if ( entry->stringOffset < storage_start || entry->stringOffset + entry->stringLength > storage_limit ) { /* invalid entry - ignore it */ entry->stringOffset = 0; entry->stringLength = 0; continue; } entry++; } table->numNameRecords = (FT_UInt)( entry - table->names ); } FT_FRAME_EXIT(); /* everything went well, update face->num_names */ face->num_names = (FT_UShort) table->numNameRecords; Exit: return error; }
/* synthesized into a TTC with one offset table. */ static FT_Error sfnt_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error; FT_ULong tag, offset; static const FT_Frame_Field ttc_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TTC_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_LONG( version ), FT_FRAME_LONG( count ), FT_FRAME_END }; face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; if ( tag != 0x00010000UL && tag != TTAG_ttcf && tag != FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) && tag != TTAG_true && tag != 0x00020000UL ) return SFNT_Err_Unknown_File_Format; face->ttc_header.tag = TTAG_ttcf; if ( tag == TTAG_ttcf ) { FT_Int n; FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) return error; /* now read the offsets of each font in the file */ if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) return error; for ( n = 0; n < face->ttc_header.count; n++ ) face->ttc_header.offsets[n] = FT_GET_ULONG(); FT_FRAME_EXIT(); } else { FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; if ( FT_NEW( face->ttc_header.offsets) ) return error; face->ttc_header.offsets[0] = offset; } return error; }
pcf_load_font( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_Bool hasBDFAccelerators; error = pcf_read_TOC( stream, face ); if ( error ) goto Exit; error = pcf_get_properties( stream, face ); if ( error ) goto Exit; /* Use the old accelerators if no BDF accelerators are in the file. */ hasBDFAccelerators = pcf_has_table_type( face->toc.tables, face->toc.count, PCF_BDF_ACCELERATORS ); if ( !hasBDFAccelerators ) { error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); if ( error ) goto Exit; } /* metrics */ error = pcf_get_metrics( stream, face ); if ( error ) goto Exit; /* bitmaps */ error = pcf_get_bitmaps( stream, face ); if ( error ) goto Exit; /* encodings */ error = pcf_get_encodings( stream, face ); if ( error ) goto Exit; /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ if ( hasBDFAccelerators ) { error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); if ( error ) goto Exit; } /* XXX: TO DO: inkmetrics and glyph_names are missing */ /* now construct the face object */ { FT_Face root = FT_FACE( face ); PCF_Property prop; root->num_faces = 1; root->face_index = 0; root->face_flags = FT_FACE_FLAG_FIXED_SIZES | FT_FACE_FLAG_HORIZONTAL | FT_FACE_FLAG_FAST_GLYPHS; if ( face->accel.constantWidth ) root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; if ( ( error = pcf_interpret_style( face ) ) != 0 ) goto Exit; prop = pcf_find_property( face, "FAMILY_NAME" ); if ( prop && prop->isString ) { if ( FT_STRDUP( root->family_name, prop->value.atom ) ) goto Exit; } else root->family_name = NULL; /* * Note: We shift all glyph indices by +1 since we must * respect the convention that glyph 0 always corresponds * to the `missing glyph'. * * This implies bumping the number of `available' glyphs by 1. */ root->num_glyphs = face->nmetrics + 1; root->num_fixed_sizes = 1; if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) goto Exit; { FT_Bitmap_Size* bsize = root->available_sizes; FT_Short resolution_x = 0, resolution_y = 0; FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); #if 0 bsize->height = face->accel.maxbounds.ascent << 6; #endif bsize->height = (FT_Short)( face->accel.fontAscent + face->accel.fontDescent ); prop = pcf_find_property( face, "AVERAGE_WIDTH" ); if ( prop ) bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); else bsize->width = (FT_Short)( bsize->height * 2/3 ); prop = pcf_find_property( face, "POINT_SIZE" ); if ( prop ) /* convert from 722.7 decipoints to 72 points per inch */ bsize->size = (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); prop = pcf_find_property( face, "PIXEL_SIZE" ); if ( prop ) bsize->y_ppem = (FT_Short)prop->value.l << 6; prop = pcf_find_property( face, "RESOLUTION_X" ); if ( prop ) resolution_x = (FT_Short)prop->value.l; prop = pcf_find_property( face, "RESOLUTION_Y" ); if ( prop ) resolution_y = (FT_Short)prop->value.l; if ( bsize->y_ppem == 0 ) { bsize->y_ppem = bsize->size; if ( resolution_y ) bsize->y_ppem = bsize->y_ppem * resolution_y / 72; } if ( resolution_x && resolution_y ) bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; else bsize->x_ppem = bsize->y_ppem; } /* set up charset */ { PCF_Property charset_registry = 0, charset_encoding = 0; charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); if ( charset_registry && charset_registry->isString && charset_encoding && charset_encoding->isString ) { if ( FT_STRDUP( face->charset_encoding, charset_encoding->value.atom ) || FT_STRDUP( face->charset_registry, charset_registry->value.atom ) ) goto Exit; } } } Exit: if ( error ) { /* This is done to respect the behaviour of the original */ /* PCF font driver. */ error = PCF_Err_Invalid_File_Format; } return error; }
pfr_phy_font_load( PFR_PhyFont phy_font, FT_Stream stream, FT_UInt32 offset, FT_UInt32 size ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt flags, num_aux; FT_Byte* p; FT_Byte* limit; phy_font->memory = memory; phy_font->offset = offset; if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) goto Exit; p = stream->cursor; limit = p + size; PFR_CHECK( 15 ); phy_font->font_ref_number = PFR_NEXT_USHORT( p ); phy_font->outline_resolution = PFR_NEXT_USHORT( p ); phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); phy_font->flags = flags = PFR_NEXT_BYTE( p ); /* get the standard advance for non-proprotional fonts */ if ( !(flags & PFR_PHY_PROPORTIONAL) ) { PFR_CHECK( 2 ); phy_font->standard_advance = PFR_NEXT_SHORT( p ); } /* load the extra items when present */ if ( flags & PFR_PHY_EXTRA_ITEMS ) { error = pfr_extra_items_parse( &p, limit, pfr_phy_font_extra_items, phy_font ); if ( error ) goto Fail; } /* skip the aux bytes */ PFR_CHECK( 3 ); num_aux = PFR_NEXT_ULONG( p ); PFR_CHECK( num_aux ); p += num_aux; /* read the blue values */ { FT_UInt n, count; PFR_CHECK( 1 ); phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); PFR_CHECK( count * 2 ); if ( FT_NEW_ARRAY( phy_font->blue_values, count ) ) goto Fail; for ( n = 0; n < count; n++ ) phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); } PFR_CHECK( 8 ); phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); phy_font->blue_scale = PFR_NEXT_BYTE( p ); phy_font->vertical.standard = PFR_NEXT_USHORT( p ); phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); /* read the character descriptors */ { FT_UInt n, count, Size; phy_font->num_chars = count = PFR_NEXT_USHORT( p ); phy_font->chars_offset = offset + ( p - stream->cursor ); if ( FT_NEW_ARRAY( phy_font->chars, count ) ) goto Fail; Size = 1 + 1 + 2; if ( flags & PFR_PHY_2BYTE_CHARCODE ) Size += 1; if ( flags & PFR_PHY_PROPORTIONAL ) Size += 2; if ( flags & PFR_PHY_ASCII_CODE ) Size += 1; if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) Size += 1; if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) Size += 1; PFR_CHECK( count * Size ); for ( n = 0; n < count; n++ ) { PFR_Char cur = &phy_font->chars[n]; cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) ? PFR_NEXT_USHORT( p ) : PFR_NEXT_BYTE( p ); cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) ? PFR_NEXT_SHORT( p ) : phy_font->standard_advance; #if 0 cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) ? PFR_NEXT_BYTE( p ) : 0; #else if ( flags & PFR_PHY_ASCII_CODE ) p += 1; #endif cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) ? PFR_NEXT_USHORT( p ) : PFR_NEXT_BYTE( p ); cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) ? PFR_NEXT_ULONG( p ) : PFR_NEXT_USHORT( p ); } } /* that's it !! */ Fail: FT_FRAME_EXIT(); Exit: return error; Too_Short: error = PFR_Err_Invalid_Table; FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); goto Fail; }