From 5b401bb918e89d1101cf714d04181b527dae7d03 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 29 May 2000 23:03:15 +0000 Subject: [PATCH] additional changes to the CFF/Type2 driver --- include/freetype/internal/t2types.h | 177 ++++++++++++ include/freetype/tttags.h | 4 + src/cff/t2load.c | 408 +++++++++++++++++----------- src/cff/t2objs.c | 27 +- src/cff/t2parse.h | 3 + 5 files changed, 461 insertions(+), 158 deletions(-) create mode 100644 include/freetype/internal/t2types.h diff --git a/include/freetype/internal/t2types.h b/include/freetype/internal/t2types.h new file mode 100644 index 000000000..f031a0bd9 --- /dev/null +++ b/include/freetype/internal/t2types.h @@ -0,0 +1,177 @@ +/***************************************************************************/ +/* */ +/* t2types.h */ +/* */ +/* Basic OpenType/CFF type definitions and interface (specification */ +/* only). */ +/* */ +/* This code is used by the OpenType/CFF driver. */ +/* */ +/* */ +/* Copyright 1996-2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef T2TYPES_H +#define T2TYPES_H + + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + /************************************************************************* + * + * + * CFF_Index + * + * + * A structure used to model a CFF Index table + * + * + * count :: number of elements in index + * off_size :: size in bytes of object offsets in index + * data_offset :: position of first data byte in the index's bytes + * + * total_size :: total_size of index in bytes + * bytes :: when the index is loaded in memory, its bytes + * file_offset :: position of index in file. The offset table starts + * at file_offset + 3 + */ + typedef struct CFF_Index_ + { + FT_Stream stream; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + + FT_ULong* offsets; + FT_Byte* bytes; + + } CFF_Index; + + + typedef struct CFF_Top_Dict_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Pos underline_position; + FT_Pos underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; + FT_UInt base_font_name; + FT_UInt postscript; + + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_ULong cid_supplement; + + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_Long cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + + } CFF_Top_Dict; + + typedef struct CFF_Private_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Pos blue_values[14]; + FT_Pos other_blues[10]; + FT_Pos family_blues[14]; + FT_Pos family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + + } CFF_Private; + + typedef struct CFF_Font_ + { + FT_Stream stream; + FT_Memory memory; + FT_UInt num_faces; + + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + FT_Byte absolute_offsize; + + + CFF_Index name_index; + CFF_Index top_dict_index; + CFF_Index string_index; + CFF_Index global_subrs_index; + + /* we don't load the Encoding and CharSet tables */ + + CFF_Index charstrings_index; + CFF_Index font_dict_index; + CFF_Index private_index; + CFF_Index local_subrs_index; + + FT_String* font_name; + CFF_Top_Dict top_dict; + CFF_Private private_dict; + + } CFF_Font; + +#ifdef __cplusplus + } +#endif + +#endif /* T2TYPES_H */ +/* END */ diff --git a/include/freetype/tttags.h b/include/freetype/tttags.h index c38470aac..f7e9af5ec 100644 --- a/include/freetype/tttags.h +++ b/include/freetype/tttags.h @@ -24,11 +24,13 @@ #define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) #define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) #define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) #define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) #define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) #define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) #define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) #define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) #define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) @@ -40,6 +42,8 @@ #define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) #define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) #define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) #define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) #define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) #define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) diff --git a/src/cff/t2load.c b/src/cff/t2load.c index b33aae587..a856542e7 100644 --- a/src/cff/t2load.c +++ b/src/cff/t2load.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,8 @@ #define FT_COMPONENT trace_ttload /* read a CFF offset from memory */ - LOCAL_FUNC - FT_ULong T2_Get_Offset( FT_Byte* p, + static + FT_ULong t2_get_offset( FT_Byte* p, FT_Byte off_size ) { FT_ULong result; @@ -41,184 +42,221 @@ } -#if 0 - /* read a CFF offset from a stream */ - LOCAL_FUNC - FT_ULong T2_Read_Offset( FT_Byte off_size, - FT_Stream stream ) - { - FT_Byte bytes[4]; - FT_Byte* p; - FT_ULong result; - if (off_size > 4) - off_size = 4; - - /* first of all, read or access the bytes - this should really go */ - /* in "src/base/ftstream.c", but there are great chances that it will */ - /* never be used elsewhere, so.. */ - if (stream->read) - { - p = bytes; - if ( stream->read( stream, stream->pos, (char*)bytes, off_size ) != off_size ) - goto Fail; - } - else - { - p = (FT_Byte*)stream->base + stream->pos; - if (p+off_size-1 >= (FT_Byte*)stream->limit) - goto Fail; - } - - result = 0; - while (off_size > 0) - { - result = (result <<= 8) | *p++; - off_size--; - } - stream->pos += off_size; - return result; - - Fail: - FT_ERROR(( "T2_Read_Offset:" )); - FT_ERROR(( " invalid i/o, pos = 0x%lx, size = 0x%lx", - stream->pos, stream->size )); - return 0; - } -#endif - - /* return the memory address of a CFF index's element, when the index */ - /* is already loaded in memory.. */ - - LOCAL_FUNC - FT_Error T2_Access_Element( CFF_Index* cff_index, - FT_UInt element, - FT_Byte* *pbytes, - FT_ULong *pbyte_len ) + static + FT_Error t2_new_cff_index( CFF_Index* index, + FT_Stream stream, + FT_Bool load ) { FT_Error error; - - if (cff_index && cff_index->bytes && element < (FT_UInt)cff_index->count) - { - FT_ULong off1, off2; - FT_Byte offsize = cff_index->off_size; - FT_Byte* p = cff_index->bytes + 3 + element*offsize; - FT_Byte* limit = cff_index->bytes + cff_index->data_offset; - - /* read element offset */ - off1 = T2_Get_Offset(p,offsize); - - /* a value of 0 indicates no object !! */ - if (off1) - { - /* compute offset of next element - skip empty elements */ - do - { - p += offsize; - off2 = T2_Get_Offset(p,offsize); - } - while (off2 == 0 && p < limit); - - if (p >= limit) - off1 = 0; - } - - *pbytes = 0; - *pbyte_len = 0; - if (off1) - { - *pbytes = cff_index->bytes + cff_index->data_offset + off1 - 1; - *pbyte_len = off2 - off1; - } - error = 0; - } - else - error = FT_Err_Invalid_Argument; - - return error; - } - - - LOCAL_FUNC - - LOCAL_FUNC - FT_Error T2_Read_CFF_Index( CFF_Index* index, - FT_Stream stream ) - { - FT_Error error; - FT_ULong data_size; + FT_Memory memory = stream->memory; + FT_UShort count; MEM_Set( index, 0, sizeof(*index) ); - index->file_offset = FILE_Pos(); - if ( !READ_UShort( index->count ) && - index->count > 0 ) + if ( !READ_UShort( count ) && + count > 0 ) { FT_Byte* p; FT_Byte offsize; + FT_ULong data_size; + FT_ULong* poff; /* there is at least one element, read the offset size */ /* then access the offset table to compute the index's total size */ if ( READ_Byte( offsize ) ) goto Exit; - index->off_size = offsize; - index->data_offset = ((FT_Long)index->count + 1)*offsize; + index->stream = stream; + index->count = count; + index->off_size = offsize; + data_size = (FT_ULong)(count+1) * offsize; - if (ACCESS_Frame( index->data_offset )) + if ( ALLOC_ARRAY( index->offsets, count+1, FT_ULong ) || + ACCESS_Frame( data_size )) goto Exit; - /* now read element offset limit */ - p = (FT_Byte*)stream->cursor + index->data_offset - offsize; - data_size = T2_Get_Offset( p, offsize ); + poff = index->offsets; + p = (FT_Byte*)stream->cursor; + for ( ; (FT_Short)count >= 0; count-- ) + { + poff[0] = t2_get_offset( p, offsize ); + poff++; + p += offsize; + } FORGET_Frame(); - index->data_offset += 3; - index->total_size = index->data_offset + data_size; + index->data_offset = FILE_Pos(); + data_size = poff[-1]-1; - /* skip the data */ - (void)FILE_Skip( data_size ); + if (load) + { + /* load the data */ + if ( EXTRACT_Frame( data_size, index->bytes ) ) + goto Exit; + } + else + { + /* skip the data */ + (void)FILE_Skip( data_size ); + } } Exit: + if (error) + FREE( index->offsets ); + return error; } - LOCAL_FUNC - FT_Error T2_Load_CFF_Index( CFF_Index* index, - FT_Stream stream ) - { - FT_Error error; - - /* we begin by reading the index's data */ - error = T2_Read_CFF_Index( index, stream ); - if (!error && index->total_size > 0) - { - /* OK, read it from the file */ - if ( FILE_Seek( index->file_offset ) || - EXTRACT_Frame( index->total_size, index->bytes ) ) - goto Exit; - - /* done !! */ - } - Exit: - return error; - } - - - LOCAL_FUNC - void T2_Done_CFF_Index( CFF_Index* index, - FT_Stream stream ) + static + void t2_done_cff_index( CFF_Index* index ) { + FT_Stream stream = index->stream; + FT_Memory memory = stream->memory; + if (index->bytes) RELEASE_Frame( index->bytes ); + FREE( index->offsets ); MEM_Set( index, 0, sizeof(*index) ); } + static + FT_Error t2_access_element( CFF_Index* index, + FT_UInt element, + FT_Byte* *pbytes, + FT_ULong *pbyte_len ) + { + FT_Error error = 0; + + if ( index && index->count > element ) + { + /* compute start and end offsets */ + FT_ULong off1, off2; + + off1 = index->offsets[element]; + if (off1) + { + do + { + element++; + off2 = index->offsets[element]; + } + while (off2 == 0 && element < index->count); + if (!off2) + off1 = 0; + } + + /* access element */ + if (off1) + { + *pbyte_len = off2 - off1; + + if (index->bytes) + { + /* this index was completely loaded in memory, that's easy */ + *pbytes = index->bytes + off1 - 1; + } + else + { + /* this index is still on disk/file, access it through a frame */ + FT_Stream stream = index->stream; + + if ( FILE_Seek( index->data_offset + off1 - 1 ) || + EXTRACT_Frame( off2-off1, *pbytes ) ) + goto Exit; + } + } + else + { + /* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = FT_Err_Invalid_Argument; + + Exit: + return error; + } + + + static + void t2_forget_element( CFF_Index* index, + FT_Byte* *pbytes ) + { + if (index->bytes == 0) + { + FT_Stream stream = index->stream; + RELEASE_Frame( *pbytes ); + } + } + + + static + FT_String* t2_get_name( CFF_Index* index, + FT_UInt element ) + { + FT_Memory memory = index->stream->memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = 0; + + error = t2_access_element( index, element, &bytes, &byte_len ); + if (error) goto Exit; + + if ( !ALLOC( name, byte_len+1 ) ) + { + MEM_Copy( name, bytes, byte_len ); + name[byte_len] = 0; + } + t2_forget_element( index, &bytes ); + + Exit: + return name; + } + + +#if 0 + LOCAL_FUNC + FT_String* T2_Get_String( CFF_Index* index, + FT_UInt sid, + PSNames_Interface* interface ) + { + /* if it's not a standard string, return it */ + if ( sid > 390 ) + return t2_get_name( index, sid - 390 ); + + /* that's a standard string, fetch a copy from the psnamed module */ + { + FT_String* name = 0; + const char* adobe_name = interface->adobe_std_strings( sid ); + FT_UInt len; + + if (adobe_name) + { + FT_Memory memory = index->stream->memory; + FT_Error error; + + len = (FT_UInt)strlen(adobe_name); + if ( !ALLOC( name, len+1 ) ) + { + MEM_Copy( name, adobe_name, len ); + name[len] = 0; + } + } + return name; + } + } +#endif + LOCAL_FUNC FT_Error T2_Load_CFF_Font( FT_Stream stream, + FT_Int face_index, CFF_Font* font ) { static const FT_Frame_Field cff_header_fields[] = { @@ -230,10 +268,13 @@ FT_FRAME_END }; FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; MEM_Set( font, 0, sizeof(*font) ); font->stream = stream; - font->memory = stream->memory; + font->memory = memory; + base_offset = FILE_Pos(); /* read CFF font header */ if ( READ_Fields( cff_header_fields, font ) ) @@ -252,15 +293,71 @@ /* skip the rest of the header */ (void)FILE_Skip( font->header_size - 4 ); - /* read the name, top dict, strong and global subrs index */ - error = T2_Load_CFF_Index( &font->name_index, stream ) || - T2_Load_CFF_Index( &font->top_dict_index, stream ) || - T2_Read_CFF_Index( &font->string_index, stream ) || - T2_Load_CFF_Index( &font->global_subrs_index, stream ); + /* read the name, top dict, string and global subrs index */ + error = t2_new_cff_index( &font->name_index, stream, 0 ) || + t2_new_cff_index( &font->top_dict_index, stream, 0 ) || + t2_new_cff_index( &font->string_index, stream, 0 ) || + t2_new_cff_index( &font->global_subrs_index, stream, 1 ); if (error) goto Exit; - /* well, we don't really forget the "disable" fonts.. */ + /* well, we don't really forget the "disabled" fonts.. */ font->num_faces = font->name_index.count; + if (face_index >= font->num_faces) + { + FT_ERROR(( "T2.Load_Font: incorrect face index = %d\n", face_index )); + error = FT_Err_Invalid_Argument; + } + + /* in case of a font format check, simply exit now */ + if (face_index >= 0) + { + T2_Parser parser; + FT_Byte* dict; + FT_ULong dict_len; + CFF_Index* index = &font->top_dict_index; + + /* parse the top-level font dictionary */ + T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->top_dict ); + + error = t2_access_element( index, face_index, &dict, &dict_len ) || + T2_Parser_Run( &parser, dict, dict + dict_len ); + + t2_forget_element( &font->top_dict_index, &dict ); + if (error) goto Exit; + + /* parse the private dictionary, if any */ + if (font->top_dict.private_offset && font->top_dict.private_size) + { + T2_Parser_Init( &parser, T2CODE_PRIVATE, &font->private_dict ); + + if ( FILE_Seek( base_offset + font->top_dict.private_offset ) || + ACCESS_Frame( font->top_dict.private_size ) ) + goto Exit; + + error = T2_Parser_Run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FORGET_Frame(); + if (error) goto Exit; + } + + /* read the charstrings index now */ + if ( font->top_dict.charstrings_offset == 0 ) + { + FT_ERROR(( "T2.New_CFF_Font: no charstrings offset !!\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + if ( FILE_Seek( base_offset + font->top_dict.charstrings_offset ) ) + goto Exit; + + error = t2_new_cff_index( &font->charstrings_index, stream, 0 ); + if (error) goto Exit; + } + + /* get the font name */ + font->font_name = t2_get_name( &font->name_index, face_index ); Exit: return error; @@ -269,12 +366,11 @@ LOCAL_FUNC void T2_Done_CFF_Font( CFF_Font* font ) { - FT_Stream stream = font->stream; - - T2_Done_CFF_Index( &font->global_subrs_index, stream ); - T2_Done_CFF_Index( &font->string_index, stream ); - T2_Done_CFF_Index( &font->top_dict_index, stream ); - T2_Done_CFF_Index( &font->name_index, stream ); + t2_done_cff_index( &font->global_subrs_index ); + t2_done_cff_index( &font->string_index ); + t2_done_cff_index( &font->top_dict_index ); + t2_done_cff_index( &font->name_index ); + t2_done_cff_index( &font->charstrings_index ); } diff --git a/src/cff/t2objs.c b/src/cff/t2objs.c index 10fc38ec5..f87d0dd95 100644 --- a/src/cff/t2objs.c +++ b/src/cff/t2objs.c @@ -97,6 +97,21 @@ error = sfnt->load_face( stream, face, face_index, num_params, params ); if ( error ) goto Exit; + /* now, load the CFF part of the file.. */ + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + if (error) goto Exit; + + { + CFF_Font* cff; + FT_Memory memory = face->root.memory; + + if ( ALLOC( cff, sizeof(*cff) ) ) + goto Exit; + + face->other = cff; + error = T2_Load_CFF_Font( stream, face_index, cff ); + } + Exit: return error; Bad_Format: @@ -120,16 +135,24 @@ LOCAL_DEF void T2_Done_Face( T2_Face face ) { -#if 0 FT_Memory memory = face->root.memory; +#if 0 FT_Stream stream = face->root.stream; #endif + SFNT_Interface* sfnt = face->sfnt; if (sfnt) sfnt->done_face(face); - /* XXXXX: TO DO */ + { + CFF_Font* cff = (CFF_Font*)face->other; + if (cff) + { + T2_Done_CFF_Font(cff); + FREE(face->other); + } + } } diff --git a/src/cff/t2parse.h b/src/cff/t2parse.h index 75aa48eb0..840cfb7ac 100644 --- a/src/cff/t2parse.h +++ b/src/cff/t2parse.h @@ -6,6 +6,9 @@ #define T2_MAX_STACK_DEPTH 96 +#define T2CODE_TOPDICT 0x1000 +#define T2CODE_PRIVATE 0x2000 + typedef struct T2_Parser_ { FT_Byte* start;