summaryrefslogtreecommitdiffstats
path: root/modules/freetype2/src/cff
diff options
context:
space:
mode:
Diffstat (limited to 'modules/freetype2/src/cff')
-rw-r--r--modules/freetype2/src/cff/cff.c28
-rw-r--r--modules/freetype2/src/cff/cffcmap.c231
-rw-r--r--modules/freetype2/src/cff/cffcmap.h67
-rw-r--r--modules/freetype2/src/cff/cffdrivr.c1218
-rw-r--r--modules/freetype2/src/cff/cffdrivr.h35
-rw-r--r--modules/freetype2/src/cff/cfferrs.h42
-rw-r--r--modules/freetype2/src/cff/cffgload.c760
-rw-r--r--modules/freetype2/src/cff/cffgload.h62
-rw-r--r--modules/freetype2/src/cff/cffload.c2579
-rw-r--r--modules/freetype2/src/cff/cffload.h124
-rw-r--r--modules/freetype2/src/cff/cffobjs.c1214
-rw-r--r--modules/freetype2/src/cff/cffobjs.h84
-rw-r--r--modules/freetype2/src/cff/cffparse.c1621
-rw-r--r--modules/freetype2/src/cff/cffparse.h148
-rw-r--r--modules/freetype2/src/cff/cfftoken.h150
-rw-r--r--modules/freetype2/src/cff/module.mk23
-rw-r--r--modules/freetype2/src/cff/rules.mk75
17 files changed, 8461 insertions, 0 deletions
diff --git a/modules/freetype2/src/cff/cff.c b/modules/freetype2/src/cff/cff.c
new file mode 100644
index 0000000000..b486c389e1
--- /dev/null
+++ b/modules/freetype2/src/cff/cff.c
@@ -0,0 +1,28 @@
+/****************************************************************************
+ *
+ * cff.c
+ *
+ * FreeType OpenType driver component (body only).
+ *
+ * Copyright (C) 1996-2023 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.
+ *
+ */
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "cffcmap.c"
+#include "cffdrivr.c"
+#include "cffgload.c"
+#include "cffparse.c"
+#include "cffload.c"
+#include "cffobjs.c"
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffcmap.c b/modules/freetype2/src/cff/cffcmap.c
new file mode 100644
index 0000000000..6ed3143222
--- /dev/null
+++ b/modules/freetype2/src/cff/cffcmap.c
@@ -0,0 +1,231 @@
+/****************************************************************************
+ *
+ * cffcmap.c
+ *
+ * CFF character mapping table (cmap) support (body).
+ *
+ * Copyright (C) 2002-2023 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include <freetype/internal/ftdebug.h>
+#include "cffcmap.h"
+#include "cffload.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_cmap_encoding_init( CFF_CMapStd cmap,
+ FT_Pointer pointer )
+ {
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Encoding encoding = &cff->encoding;
+
+ FT_UNUSED( pointer );
+
+
+ cmap->gids = encoding->codes;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ cff_cmap_encoding_done( CFF_CMapStd cmap )
+ {
+ cmap->gids = NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_encoding_char_index( CFF_CMapStd cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt result = 0;
+
+
+ if ( char_code < 256 )
+ result = cmap->gids[char_code];
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt32 )
+ cff_cmap_encoding_char_next( CFF_CMapStd cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
+
+
+ *pchar_code = 0;
+
+ if ( char_code < 255 )
+ {
+ FT_UInt code = (FT_UInt)( char_code + 1 );
+
+
+ for (;;)
+ {
+ if ( code >= 256 )
+ break;
+
+ result = cmap->gids[code];
+ if ( result != 0 )
+ {
+ *pchar_code = code;
+ break;
+ }
+
+ code++;
+ }
+ }
+ return result;
+ }
+
+
+ FT_DEFINE_CMAP_CLASS(
+ cff_cmap_encoding_class_rec,
+
+ sizeof ( CFF_CMapStdRec ),
+
+ (FT_CMap_InitFunc) cff_cmap_encoding_init, /* init */
+ (FT_CMap_DoneFunc) cff_cmap_encoding_done, /* done */
+ (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, /* char_index */
+ (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, /* char_next */
+
+ (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */
+ (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */
+ (FT_CMap_VariantListFunc) NULL, /* variant_list */
+ (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */
+ (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */
+ )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( const char* )
+ cff_sid_to_glyph_name( TT_Face face,
+ FT_UInt idx )
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Charset charset = &cff->charset;
+ FT_UInt sid = charset->sids[idx];
+
+
+ return cff_index_get_sid_string( cff, sid );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_cmap_unicode_init( PS_Unicodes unicodes,
+ FT_Pointer pointer )
+ {
+ TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Charset charset = &cff->charset;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+
+ FT_UNUSED( pointer );
+
+
+ /* can't build Unicode map for CID-keyed font */
+ /* because we don't know glyph names. */
+ if ( !charset->sids )
+ return FT_THROW( No_Unicode_Glyph_Name );
+
+ if ( !psnames->unicodes_init )
+ return FT_THROW( Unimplemented_Feature );
+
+ return psnames->unicodes_init( memory,
+ unicodes,
+ cff->num_glyphs,
+ (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name,
+ (PS_FreeGlyphNameFunc)NULL,
+ (FT_Pointer)face );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ cff_cmap_unicode_done( PS_Unicodes unicodes )
+ {
+ FT_Face face = FT_CMAP_FACE( unicodes );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( unicodes->maps );
+ unicodes->num_maps = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_unicode_char_index( PS_Unicodes unicodes,
+ FT_UInt32 char_code )
+ {
+ TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+
+
+ return psnames->unicodes_char_index( unicodes, char_code );
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt32 )
+ cff_cmap_unicode_char_next( PS_Unicodes unicodes,
+ FT_UInt32 *pchar_code )
+ {
+ TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+
+
+ return psnames->unicodes_char_next( unicodes, pchar_code );
+ }
+
+
+ FT_DEFINE_CMAP_CLASS(
+ cff_cmap_unicode_class_rec,
+
+ sizeof ( PS_UnicodesRec ),
+
+ (FT_CMap_InitFunc) cff_cmap_unicode_init, /* init */
+ (FT_CMap_DoneFunc) cff_cmap_unicode_done, /* done */
+ (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, /* char_index */
+ (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, /* char_next */
+
+ (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */
+ (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */
+ (FT_CMap_VariantListFunc) NULL, /* variant_list */
+ (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */
+ (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */
+ )
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffcmap.h b/modules/freetype2/src/cff/cffcmap.h
new file mode 100644
index 0000000000..b2afc2fab6
--- /dev/null
+++ b/modules/freetype2/src/cff/cffcmap.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+ *
+ * cffcmap.h
+ *
+ * CFF character mapping table (cmap) support (specification).
+ *
+ * Copyright (C) 2002-2023 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 CFFCMAP_H_
+#define CFFCMAP_H_
+
+#include <freetype/internal/cffotypes.h>
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* standard (and expert) encoding cmaps */
+ typedef struct CFF_CMapStdRec_* CFF_CMapStd;
+
+ typedef struct CFF_CMapStdRec_
+ {
+ FT_CMapRec cmap;
+ FT_UShort* gids; /* up to 256 elements */
+
+ } CFF_CMapStdRec;
+
+
+ FT_DECLARE_CMAP_CLASS( cff_cmap_encoding_class_rec )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* unicode (synthetic) cmaps */
+
+ FT_DECLARE_CMAP_CLASS( cff_cmap_unicode_class_rec )
+
+
+FT_END_HEADER
+
+#endif /* CFFCMAP_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffdrivr.c b/modules/freetype2/src/cff/cffdrivr.c
new file mode 100644
index 0000000000..4e2e0e00de
--- /dev/null
+++ b/modules/freetype2/src/cff/cffdrivr.c
@@ -0,0 +1,1218 @@
+/****************************************************************************
+ *
+ * cffdrivr.c
+ *
+ * OpenType font driver implementation (body).
+ *
+ * Copyright (C) 1996-2023 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include <freetype/freetype.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/sfnt.h>
+#include <freetype/internal/psaux.h>
+#include <freetype/internal/ftpsprop.h>
+#include <freetype/internal/services/svcid.h>
+#include <freetype/internal/services/svpsinfo.h>
+#include <freetype/internal/services/svpostnm.h>
+#include <freetype/internal/services/svttcmap.h>
+#include <freetype/internal/services/svcfftl.h>
+
+#include "cffdrivr.h"
+#include "cffgload.h"
+#include "cffload.h"
+#include "cffcmap.h"
+#include "cffparse.h"
+#include "cffobjs.h"
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include <freetype/internal/services/svmm.h>
+#include <freetype/internal/services/svmetric.h>
+#endif
+
+#include "cfferrs.h"
+
+#include <freetype/internal/services/svfntfmt.h>
+#include <freetype/internal/services/svgldict.h>
+#include <freetype/internal/services/svprop.h>
+#include <freetype/ftdriver.h>
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT cffdriver
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F A C E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * cff_get_kerning
+ *
+ * @Description:
+ * A driver method used to return the kerning vector between two
+ * glyphs of the same face.
+ *
+ * @Input:
+ * face ::
+ * A handle to the source face object.
+ *
+ * left_glyph ::
+ * The index of the left glyph in the kern pair.
+ *
+ * right_glyph ::
+ * The index of the right glyph in the kern pair.
+ *
+ * @Output:
+ * kerning ::
+ * The kerning vector. This is in font units for
+ * scalable formats, and in pixels for fixed-sizes
+ * formats.
+ *
+ * @Return:
+ * FreeType error code. 0 means success.
+ *
+ * @Note:
+ * Only horizontal layouts (left-to-right & right-to-left) are
+ * supported by this function. Other layouts, or more sophisticated
+ * kernings, are out of scope of this method (the basic driver
+ * interface is meant to be simple).
+ *
+ * They can be implemented by format-specific interfaces.
+ */
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_kerning( FT_Face ttface, /* TT_Face */
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ TT_Face face = (TT_Face)ttface;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ if ( sfnt )
+ kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+
+ return FT_Err_Ok;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * cff_glyph_load
+ *
+ * @Description:
+ * A driver method used to load a glyph within a given glyph slot.
+ *
+ * @Input:
+ * slot ::
+ * A handle to the target slot object where the glyph
+ * will be loaded.
+ *
+ * size ::
+ * A handle to the source face size at which the glyph
+ * must be scaled, loaded, etc.
+ *
+ * glyph_index ::
+ * The index of the glyph in the font file.
+ *
+ * load_flags ::
+ * A flag indicating what to load for this glyph. The
+ * FT_LOAD_??? constants can be used to control the
+ * glyph loading process (e.g., whether the outline
+ * should be scaled, whether to load bitmaps or not,
+ * whether to hint the outline, etc).
+ *
+ * @Return:
+ * FreeType error code. 0 means success.
+ */
+ FT_CALLBACK_DEF( FT_Error )
+ cff_glyph_load( FT_GlyphSlot cffslot, /* CFF_GlyphSlot */
+ FT_Size cffsize, /* CFF_Size */
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ CFF_GlyphSlot slot = (CFF_GlyphSlot)cffslot;
+ CFF_Size size = (CFF_Size)cffsize;
+
+
+ if ( !slot )
+ return FT_THROW( Invalid_Slot_Handle );
+
+ FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
+
+ /* check whether we want a scaled outline or bitmap */
+ if ( !size )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ /* reset the size object if necessary */
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ size = NULL;
+
+ if ( size )
+ {
+ /* these two objects must have the same parent */
+ if ( cffsize->face != cffslot->face )
+ return FT_THROW( Invalid_Face_Handle );
+ }
+
+ /* now load the glyph outline if necessary */
+ error = cff_slot_load( slot, size, glyph_index, load_flags );
+
+ /* force drop-out mode to 2 - irrelevant now */
+ /* slot->outline.dropout_mode = 2; */
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_advances( FT_Face face,
+ FT_UInt start,
+ FT_UInt count,
+ FT_Int32 flags,
+ FT_Fixed* advances )
+ {
+ FT_UInt nn;
+ FT_Error error = FT_Err_Ok;
+ FT_GlyphSlot slot = face->glyph;
+
+
+ if ( FT_IS_SFNT( face ) )
+ {
+ /* OpenType 1.7 mandates that the data from `hmtx' table be used; */
+ /* it is no longer necessary that those values are identical to */
+ /* the values in the `CFF' table */
+
+ TT_Face ttface = (TT_Face)face;
+ FT_Short dummy;
+
+
+ if ( flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ /* no fast retrieval for blended MM fonts without VVAR table */
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+ return FT_THROW( Unimplemented_Feature );
+#endif
+
+ /* check whether we have data from the `vmtx' table at all; */
+ /* otherwise we extract the info from the CFF glyphstrings */
+ /* (instead of synthesizing a global value using the `OS/2' */
+ /* table) */
+ if ( !ttface->vertical_info )
+ goto Missing_Table;
+
+ for ( nn = 0; nn < count; nn++ )
+ {
+ FT_UShort ah;
+
+
+ ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
+ 1,
+ start + nn,
+ &dummy,
+ &ah );
+
+ FT_TRACE5(( " idx %d: advance height %d font unit%s\n",
+ start + nn,
+ ah,
+ ah == 1 ? "" : "s" ));
+ advances[nn] = ah;
+ }
+ }
+ else
+ {
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ /* no fast retrieval for blended MM fonts without HVAR table */
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+ return FT_THROW( Unimplemented_Feature );
+#endif
+
+ /* check whether we have data from the `hmtx' table at all */
+ if ( !ttface->horizontal.number_Of_HMetrics )
+ goto Missing_Table;
+
+ for ( nn = 0; nn < count; nn++ )
+ {
+ FT_UShort aw;
+
+
+ ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
+ 0,
+ start + nn,
+ &dummy,
+ &aw );
+
+ FT_TRACE5(( " idx %d: advance width %d font unit%s\n",
+ start + nn,
+ aw,
+ aw == 1 ? "" : "s" ));
+ advances[nn] = aw;
+ }
+ }
+
+ return error;
+ }
+
+ Missing_Table:
+ flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
+
+ for ( nn = 0; nn < count; nn++ )
+ {
+ error = cff_glyph_load( slot, face->size, start + nn, flags );
+ if ( error )
+ break;
+
+ advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
+ ? slot->linearVertAdvance
+ : slot->linearHoriAdvance;
+ }
+
+ return error;
+ }
+
+
+ /*
+ * GLYPH DICT SERVICE
+ *
+ */
+
+ static FT_Error
+ cff_get_glyph_name( CFF_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ CFF_Font font = (CFF_Font)face->extra.data;
+ FT_String* gname;
+ FT_UShort sid;
+ FT_Error error;
+
+
+ /* CFF2 table does not have glyph names; */
+ /* we need to use `post' table method */
+ if ( font->version_major == 2 )
+ {
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
+ FT_Service_GlyphDict service =
+ (FT_Service_GlyphDict)ft_module_get_service(
+ sfnt_module,
+ FT_SERVICE_ID_GLYPH_DICT,
+ 0 );
+
+
+ if ( service && service->get_name )
+ return service->get_name( FT_FACE( face ),
+ glyph_index,
+ buffer,
+ buffer_max );
+ else
+ {
+ FT_ERROR(( "cff_get_glyph_name:"
+ " cannot get glyph name from a CFF2 font\n" ));
+ FT_ERROR(( " "
+ " without the `psnames' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+ }
+
+ if ( !font->psnames )
+ {
+ FT_ERROR(( "cff_get_glyph_name:"
+ " cannot get glyph name from CFF & CEF fonts\n" ));
+ FT_ERROR(( " "
+ " without the `psnames' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+
+ /* first, locate the sid in the charset table */
+ sid = font->charset.sids[glyph_index];
+
+ /* now, lookup the name itself */
+ gname = cff_index_get_sid_string( font, sid );
+
+ if ( gname )
+ FT_STRCPYN( buffer, gname, buffer_max );
+
+ error = FT_Err_Ok;
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_UInt
+ cff_get_name_index( CFF_Face face,
+ const FT_String* glyph_name )
+ {
+ CFF_Font cff;
+ CFF_Charset charset;
+ FT_Service_PsCMaps psnames;
+ FT_String* name;
+ FT_UShort sid;
+ FT_UInt i;
+
+
+ cff = (CFF_FontRec *)face->extra.data;
+ charset = &cff->charset;
+
+ /* CFF2 table does not have glyph names; */
+ /* we need to use `post' table method */
+ if ( cff->version_major == 2 )
+ {
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
+ FT_Service_GlyphDict service =
+ (FT_Service_GlyphDict)ft_module_get_service(
+ sfnt_module,
+ FT_SERVICE_ID_GLYPH_DICT,
+ 0 );
+
+
+ if ( service && service->name_index )
+ return service->name_index( FT_FACE( face ), glyph_name );
+ else
+ {
+ FT_ERROR(( "cff_get_name_index:"
+ " cannot get glyph index from a CFF2 font\n" ));
+ FT_ERROR(( " "
+ " without the `psnames' module\n" ));
+ return 0;
+ }
+ }
+
+ FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
+ if ( !psnames )
+ return 0;
+
+ for ( i = 0; i < cff->num_glyphs; i++ )
+ {
+ sid = charset->sids[i];
+
+ if ( sid > 390 )
+ name = cff_index_get_string( cff, sid - 391 );
+ else
+ name = (FT_String *)psnames->adobe_std_strings( sid );
+
+ if ( !name )
+ continue;
+
+ if ( !ft_strcmp( glyph_name, name ) )
+ return i;
+ }
+
+ return 0;
+ }
+
+
+ FT_DEFINE_SERVICE_GLYPHDICTREC(
+ cff_service_glyph_dict,
+
+ (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, /* get_name */
+ (FT_GlyphDict_NameIndexFunc)cff_get_name_index /* name_index */
+ )
+
+
+ /*
+ * POSTSCRIPT INFO SERVICE
+ *
+ */
+
+ static FT_Int
+ cff_ps_has_glyph_names( FT_Face face )
+ {
+ return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0;
+ }
+
+
+ static FT_Error
+ cff_ps_get_font_info( CFF_Face face,
+ PS_FontInfoRec* afont_info )
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( cff && !cff->font_info )
+ {
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+ FT_Memory memory = face->root.memory;
+ PS_FontInfoRec* font_info = NULL;
+
+
+ if ( FT_QNEW( font_info ) )
+ goto Fail;
+
+ font_info->version = cff_index_get_sid_string( cff,
+ dict->version );
+ font_info->notice = cff_index_get_sid_string( cff,
+ dict->notice );
+ font_info->full_name = cff_index_get_sid_string( cff,
+ dict->full_name );
+ font_info->family_name = cff_index_get_sid_string( cff,
+ dict->family_name );
+ font_info->weight = cff_index_get_sid_string( cff,
+ dict->weight );
+ font_info->italic_angle = dict->italic_angle;
+ font_info->is_fixed_pitch = dict->is_fixed_pitch;
+ font_info->underline_position = (FT_Short)dict->underline_position;
+ font_info->underline_thickness = (FT_UShort)dict->underline_thickness;
+
+ cff->font_info = font_info;
+ }
+
+ if ( cff )
+ *afont_info = *cff->font_info;
+
+ Fail:
+ return error;
+ }
+
+
+ static FT_Error
+ cff_ps_get_font_extra( CFF_Face face,
+ PS_FontExtraRec* afont_extra )
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( cff && !cff->font_extra )
+ {
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+ FT_Memory memory = face->root.memory;
+ PS_FontExtraRec* font_extra = NULL;
+ FT_String* embedded_postscript;
+
+
+ if ( FT_QNEW( font_extra ) )
+ goto Fail;
+
+ font_extra->fs_type = 0U;
+
+ embedded_postscript = cff_index_get_sid_string(
+ cff,
+ dict->embedded_postscript );
+ if ( embedded_postscript )
+ {
+ FT_String* start_fstype;
+ FT_String* start_def;
+
+
+ /* Identify the XYZ integer in `/FSType XYZ def' substring. */
+ if ( ( start_fstype = ft_strstr( embedded_postscript,
+ "/FSType" ) ) != NULL &&
+ ( start_def = ft_strstr( start_fstype +
+ sizeof ( "/FSType" ) - 1,
+ "def" ) ) != NULL )
+ {
+ FT_String* s;
+
+
+ for ( s = start_fstype + sizeof ( "/FSType" ) - 1;
+ s != start_def;
+ s++ )
+ {
+ if ( *s >= '0' && *s <= '9' )
+ {
+ if ( font_extra->fs_type >= ( FT_USHORT_MAX - 9 ) / 10 )
+ {
+ /* Overflow - ignore the FSType value. */
+ font_extra->fs_type = 0U;
+ break;
+ }
+
+ font_extra->fs_type *= 10;
+ font_extra->fs_type += (FT_UShort)( *s - '0' );
+ }
+ else if ( *s != ' ' && *s != '\n' && *s != '\r' )
+ {
+ /* Non-whitespace character between `/FSType' and next `def' */
+ /* - ignore the FSType value. */
+ font_extra->fs_type = 0U;
+ break;
+ }
+ }
+ }
+ }
+
+ cff->font_extra = font_extra;
+ }
+
+ if ( cff )
+ *afont_extra = *cff->font_extra;
+
+ Fail:
+ return error;
+ }
+
+
+ FT_DEFINE_SERVICE_PSINFOREC(
+ cff_service_ps_info,
+
+ (PS_GetFontInfoFunc) cff_ps_get_font_info, /* ps_get_font_info */
+ (PS_GetFontExtraFunc) cff_ps_get_font_extra, /* ps_get_font_extra */
+ (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, /* ps_has_glyph_names */
+ /* unsupported with CFF fonts */
+ (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */
+ /* not implemented */
+ (PS_GetFontValueFunc) NULL /* ps_get_font_value */
+ )
+
+
+ /*
+ * POSTSCRIPT NAME SERVICE
+ *
+ */
+
+ static const char*
+ cff_get_ps_name( CFF_Face face )
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ /* following the OpenType specification 1.7, we return the name stored */
+ /* in the `name' table for a CFF wrapped into an SFNT container */
+
+ if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt )
+ {
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
+ FT_Service_PsFontName service =
+ (FT_Service_PsFontName)ft_module_get_service(
+ sfnt_module,
+ FT_SERVICE_ID_POSTSCRIPT_FONT_NAME,
+ 0 );
+
+
+ if ( service && service->get_ps_font_name )
+ return service->get_ps_font_name( FT_FACE( face ) );
+ }
+
+ return (const char*)cff->font_name;
+ }
+
+
+ FT_DEFINE_SERVICE_PSFONTNAMEREC(
+ cff_service_ps_name,
+
+ (FT_PsName_GetFunc)cff_get_ps_name /* get_ps_font_name */
+ )
+
+
+ /*
+ * TT CMAP INFO
+ *
+ * If the charmap is a synthetic Unicode encoding cmap or
+ * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO
+ * service defined in SFNT module.
+ *
+ * Otherwise call the service function in the sfnt module.
+ *
+ */
+ static FT_Error
+ cff_get_cmap_info( FT_CharMap charmap,
+ TT_CMapInfo *cmap_info )
+ {
+ FT_CMap cmap = FT_CMAP( charmap );
+ FT_Error error = FT_Err_Ok;
+
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Library library = FT_FACE_LIBRARY( face );
+
+
+ if ( cmap->clazz != &cff_cmap_encoding_class_rec &&
+ cmap->clazz != &cff_cmap_unicode_class_rec )
+ {
+ FT_Module sfnt = FT_Get_Module( library, "sfnt" );
+ FT_Service_TTCMaps service =
+ (FT_Service_TTCMaps)ft_module_get_service( sfnt,
+ FT_SERVICE_ID_TT_CMAP,
+ 0 );
+
+
+ if ( service && service->get_cmap_info )
+ error = service->get_cmap_info( charmap, cmap_info );
+ }
+ else
+ error = FT_THROW( Invalid_CharMap_Format );
+
+ return error;
+ }
+
+
+ FT_DEFINE_SERVICE_TTCMAPSREC(
+ cff_service_get_cmap_info,
+
+ (TT_CMap_Info_GetFunc)cff_get_cmap_info /* get_cmap_info */
+ )
+
+
+ /*
+ * CID INFO SERVICE
+ *
+ */
+ static FT_Error
+ cff_get_ros( CFF_Face face,
+ const char* *registry,
+ const char* *ordering,
+ FT_Int *supplement )
+ {
+ FT_Error error = FT_Err_Ok;
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+
+ if ( cff )
+ {
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+
+
+ if ( dict->cid_registry == 0xFFFFU )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Fail;
+ }
+
+ if ( registry )
+ {
+ if ( !cff->registry )
+ cff->registry = cff_index_get_sid_string( cff,
+ dict->cid_registry );
+ *registry = cff->registry;
+ }
+
+ if ( ordering )
+ {
+ if ( !cff->ordering )
+ cff->ordering = cff_index_get_sid_string( cff,
+ dict->cid_ordering );
+ *ordering = cff->ordering;
+ }
+
+ /*
+ * XXX: According to Adobe TechNote #5176, the supplement in CFF
+ * can be a real number. We truncate it to fit public API
+ * since freetype-2.3.6.
+ */
+ if ( supplement )
+ {
+ if ( dict->cid_supplement < FT_INT_MIN ||
+ dict->cid_supplement > FT_INT_MAX )
+ FT_TRACE1(( "cff_get_ros: too large supplement %ld is truncated\n",
+ dict->cid_supplement ));
+ *supplement = (FT_Int)dict->cid_supplement;
+ }
+ }
+
+ Fail:
+ return error;
+ }
+
+
+ static FT_Error
+ cff_get_is_cid( CFF_Face face,
+ FT_Bool *is_cid )
+ {
+ FT_Error error = FT_Err_Ok;
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+
+ *is_cid = 0;
+
+ if ( cff )
+ {
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+
+
+ if ( dict->cid_registry != 0xFFFFU )
+ *is_cid = 1;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_get_cid_from_glyph_index( CFF_Face face,
+ FT_UInt glyph_index,
+ FT_UInt *cid )
+ {
+ FT_Error error = FT_Err_Ok;
+ CFF_Font cff;
+
+
+ cff = (CFF_Font)face->extra.data;
+
+ if ( cff )
+ {
+ FT_UInt c;
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+
+
+ if ( dict->cid_registry == 0xFFFFU )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Fail;
+ }
+
+ if ( glyph_index >= cff->num_glyphs )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Fail;
+ }
+
+ c = cff->charset.sids[glyph_index];
+
+ if ( cid )
+ *cid = c;
+ }
+
+ Fail:
+ return error;
+ }
+
+
+ FT_DEFINE_SERVICE_CIDREC(
+ cff_service_cid_info,
+
+ (FT_CID_GetRegistryOrderingSupplementFunc)
+ cff_get_ros, /* get_ros */
+ (FT_CID_GetIsInternallyCIDKeyedFunc)
+ cff_get_is_cid, /* get_is_cid */
+ (FT_CID_GetCIDFromGlyphIndexFunc)
+ cff_get_cid_from_glyph_index /* get_cid_from_glyph_index */
+ )
+
+
+ /*
+ * PROPERTY SERVICE
+ *
+ */
+
+ FT_DEFINE_SERVICE_PROPERTIESREC(
+ cff_service_properties,
+
+ (FT_Properties_SetFunc)ps_property_set, /* set_property */
+ (FT_Properties_GetFunc)ps_property_get ) /* get_property */
+
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+ /*
+ * MULTIPLE MASTER SERVICE
+ *
+ */
+
+ static FT_Error
+ cff_set_mm_blend( CFF_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->set_mm_blend( FT_FACE( face ), num_coords, coords );
+ }
+
+
+ static FT_Error
+ cff_get_mm_blend( CFF_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_mm_blend( FT_FACE( face ), num_coords, coords );
+ }
+
+
+ static FT_Error
+ cff_set_mm_weightvector( CFF_Face face,
+ FT_UInt len,
+ FT_Fixed* weightvector )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector );
+ }
+
+
+ static FT_Error
+ cff_get_mm_weightvector( CFF_Face face,
+ FT_UInt* len,
+ FT_Fixed* weightvector )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector );
+ }
+
+
+ static FT_Error
+ cff_get_mm_var( CFF_Face face,
+ FT_MM_Var* *master )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_mm_var( FT_FACE( face ), master );
+ }
+
+
+ static FT_Error
+ cff_set_var_design( CFF_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->set_var_design( FT_FACE( face ), num_coords, coords );
+ }
+
+
+ static FT_Error
+ cff_get_var_design( CFF_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_var_design( FT_FACE( face ), num_coords, coords );
+ }
+
+
+ static FT_Error
+ cff_set_instance( CFF_Face face,
+ FT_UInt instance_index )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->set_instance( FT_FACE( face ), instance_index );
+ }
+
+
+ static FT_Error
+ cff_load_item_variation_store( CFF_Face face,
+ FT_ULong offset,
+ GX_ItemVarStore itemStore )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->load_item_var_store( FT_FACE(face), offset, itemStore );
+ }
+
+
+ static FT_Error
+ cff_load_delta_set_index_mapping( CFF_Face face,
+ FT_ULong offset,
+ GX_DeltaSetIdxMap map,
+ GX_ItemVarStore itemStore,
+ FT_ULong table_len )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->load_delta_set_idx_map( FT_FACE( face ), offset, map,
+ itemStore, table_len );
+ }
+
+
+ static FT_Int
+ cff_get_item_delta( CFF_Face face,
+ GX_ItemVarStore itemStore,
+ FT_UInt outerIndex,
+ FT_UInt innerIndex )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_item_delta( FT_FACE( face ), itemStore,
+ outerIndex, innerIndex );
+ }
+
+
+ static void
+ cff_done_item_variation_store( CFF_Face face,
+ GX_ItemVarStore itemStore )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ mm->done_item_var_store( FT_FACE( face ), itemStore );
+ }
+
+
+ static void
+ cff_done_delta_set_index_map( CFF_Face face,
+ GX_DeltaSetIdxMap deltaSetIdxMap )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ mm->done_delta_set_idx_map( FT_FACE ( face ), deltaSetIdxMap );
+ }
+
+
+
+ FT_DEFINE_SERVICE_MULTIMASTERSREC(
+ cff_service_multi_masters,
+
+ (FT_Get_MM_Func) NULL, /* get_mm */
+ (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
+ (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */
+ (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */
+ (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */
+ (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design */
+ (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design */
+ (FT_Set_Instance_Func) cff_set_instance, /* set_instance */
+ (FT_Set_MM_WeightVector_Func)
+ cff_set_mm_weightvector,
+ /* set_mm_weightvector */
+ (FT_Get_MM_WeightVector_Func)
+ cff_get_mm_weightvector,
+ /* get_mm_weightvector */
+ (FT_Var_Load_Delta_Set_Idx_Map_Func)
+ cff_load_delta_set_index_mapping,
+ /* load_delta_set_idx_map */
+ (FT_Var_Load_Item_Var_Store_Func)
+ cff_load_item_variation_store,
+ /* load_item_variation_store */
+ (FT_Var_Get_Item_Delta_Func)
+ cff_get_item_delta, /* get_item_delta */
+ (FT_Var_Done_Item_Var_Store_Func)
+ cff_done_item_variation_store,
+ /* done_item_variation_store */
+ (FT_Var_Done_Delta_Set_Idx_Map_Func)
+ cff_done_delta_set_index_map,
+ /* done_delta_set_index_map */
+ (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */
+ (FT_Done_Blend_Func) cff_done_blend /* done_blend */
+ )
+
+
+ /*
+ * METRICS VARIATIONS SERVICE
+ *
+ */
+
+ static FT_Error
+ cff_hadvance_adjust( CFF_Face face,
+ FT_UInt gindex,
+ FT_Int *avalue )
+ {
+ FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+
+
+ return var->hadvance_adjust( FT_FACE( face ), gindex, avalue );
+ }
+
+
+ static void
+ cff_metrics_adjust( CFF_Face face )
+ {
+ FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+
+
+ var->metrics_adjust( FT_FACE( face ) );
+ }
+
+
+ FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
+ cff_service_metrics_variations,
+
+ (FT_HAdvance_Adjust_Func)cff_hadvance_adjust, /* hadvance_adjust */
+ (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */
+ (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */
+
+ (FT_VAdvance_Adjust_Func)NULL, /* vadvance_adjust */
+ (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */
+ (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */
+ (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */
+
+ (FT_Metrics_Adjust_Func) cff_metrics_adjust /* metrics_adjust */
+ )
+#endif
+
+
+ /*
+ * CFFLOAD SERVICE
+ *
+ */
+
+ FT_DEFINE_SERVICE_CFFLOADREC(
+ cff_service_cff_load,
+
+ (FT_Get_Standard_Encoding_Func)cff_get_standard_encoding,
+ (FT_Load_Private_Dict_Func) cff_load_private_dict,
+ (FT_FD_Select_Get_Func) cff_fd_select_get,
+ (FT_Blend_Check_Vector_Func) cff_blend_check_vector,
+ (FT_Blend_Build_Vector_Func) cff_blend_build_vector
+ )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** D R I V E R I N T E R F A C E ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#if defined TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ FT_DEFINE_SERVICEDESCREC10(
+ cff_services,
+
+ FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF,
+ FT_SERVICE_ID_MULTI_MASTERS, &cff_service_multi_masters,
+ FT_SERVICE_ID_METRICS_VARIATIONS, &cff_service_metrics_variations,
+ FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info,
+ FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name,
+ FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict,
+ FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info,
+ FT_SERVICE_ID_CID, &cff_service_cid_info,
+ FT_SERVICE_ID_PROPERTIES, &cff_service_properties,
+ FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load
+ )
+#else
+ FT_DEFINE_SERVICEDESCREC8(
+ cff_services,
+
+ FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF,
+ FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info,
+ FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name,
+ FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict,
+ FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info,
+ FT_SERVICE_ID_CID, &cff_service_cid_info,
+ FT_SERVICE_ID_PROPERTIES, &cff_service_properties,
+ FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load
+ )
+#endif
+
+
+ FT_CALLBACK_DEF( FT_Module_Interface )
+ cff_get_interface( FT_Module driver, /* CFF_Driver */
+ const char* module_interface )
+ {
+ FT_Library library;
+ FT_Module sfnt;
+ FT_Module_Interface result;
+
+
+ result = ft_service_list_lookup( cff_services, module_interface );
+ if ( result )
+ return result;
+
+ /* `driver' is not yet evaluated */
+ if ( !driver )
+ return NULL;
+ library = driver->library;
+ if ( !library )
+ return NULL;
+
+ /* we pass our request to the `sfnt' module */
+ sfnt = FT_Get_Module( library, "sfnt" );
+
+ return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0;
+ }
+
+
+ /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#define CFF_SIZE_SELECT cff_size_select
+#else
+#define CFF_SIZE_SELECT 0
+#endif
+
+ FT_DEFINE_DRIVER(
+ cff_driver_class,
+
+ FT_MODULE_FONT_DRIVER |
+ FT_MODULE_DRIVER_SCALABLE |
+ FT_MODULE_DRIVER_HAS_HINTER |
+ FT_MODULE_DRIVER_HINTS_LIGHTLY,
+
+ sizeof ( PS_DriverRec ),
+ "cff",
+ 0x10000L,
+ 0x20000L,
+
+ NULL, /* module-specific interface */
+
+ cff_driver_init, /* FT_Module_Constructor module_init */
+ cff_driver_done, /* FT_Module_Destructor module_done */
+ cff_get_interface, /* FT_Module_Requester get_interface */
+
+ sizeof ( TT_FaceRec ),
+ sizeof ( CFF_SizeRec ),
+ sizeof ( CFF_GlyphSlotRec ),
+
+ cff_face_init, /* FT_Face_InitFunc init_face */
+ cff_face_done, /* FT_Face_DoneFunc done_face */
+ cff_size_init, /* FT_Size_InitFunc init_size */
+ cff_size_done, /* FT_Size_DoneFunc done_size */
+ cff_slot_init, /* FT_Slot_InitFunc init_slot */
+ cff_slot_done, /* FT_Slot_DoneFunc done_slot */
+
+ cff_glyph_load, /* FT_Slot_LoadFunc load_glyph */
+
+ cff_get_kerning, /* FT_Face_GetKerningFunc get_kerning */
+ NULL, /* FT_Face_AttachFunc attach_file */
+ cff_get_advances, /* FT_Face_GetAdvancesFunc get_advances */
+
+ cff_size_request, /* FT_Size_RequestFunc request_size */
+ CFF_SIZE_SELECT /* FT_Size_SelectFunc select_size */
+ )
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffdrivr.h b/modules/freetype2/src/cff/cffdrivr.h
new file mode 100644
index 0000000000..ab1f147bb2
--- /dev/null
+++ b/modules/freetype2/src/cff/cffdrivr.h
@@ -0,0 +1,35 @@
+/****************************************************************************
+ *
+ * cffdrivr.h
+ *
+ * High-level OpenType driver interface (specification).
+ *
+ * Copyright (C) 1996-2023 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 CFFDRIVER_H_
+#define CFFDRIVER_H_
+
+
+#include <freetype/internal/ftdrv.h>
+
+
+FT_BEGIN_HEADER
+
+ FT_DECLARE_DRIVER( cff_driver_class )
+
+FT_END_HEADER
+
+#endif /* CFFDRIVER_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cfferrs.h b/modules/freetype2/src/cff/cfferrs.h
new file mode 100644
index 0000000000..bc9a3043fc
--- /dev/null
+++ b/modules/freetype2/src/cff/cfferrs.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+ *
+ * cfferrs.h
+ *
+ * CFF error codes (specification only).
+ *
+ * Copyright (C) 2001-2023 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.
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * This file is used to define the CFF error enumeration constants.
+ *
+ */
+
+#ifndef CFFERRS_H_
+#define CFFERRS_H_
+
+#include <freetype/ftmoderr.h>
+
+#undef FTERRORS_H_
+
+#undef FT_ERR_PREFIX
+#define FT_ERR_PREFIX CFF_Err_
+#define FT_ERR_BASE FT_Mod_Err_CFF
+
+
+#include <freetype/fterrors.h>
+
+#endif /* CFFERRS_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffgload.c b/modules/freetype2/src/cff/cffgload.c
new file mode 100644
index 0000000000..cfa0aaf2b6
--- /dev/null
+++ b/modules/freetype2/src/cff/cffgload.c
@@ -0,0 +1,760 @@
+/****************************************************************************
+ *
+ * cffgload.c
+ *
+ * OpenType Glyph Loader (body).
+ *
+ * Copyright (C) 1996-2023 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/sfnt.h>
+#include <freetype/internal/ftcalc.h>
+#include <freetype/internal/psaux.h>
+#include <freetype/ftoutln.h>
+#include <freetype/ftdriver.h>
+
+#include "cffload.h"
+#include "cffgload.h"
+
+#include "cfferrs.h"
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#define IS_DEFAULT_INSTANCE( _face ) \
+ ( !( FT_IS_NAMED_INSTANCE( _face ) || \
+ FT_IS_VARIATION( _face ) ) )
+#else
+#define IS_DEFAULT_INSTANCE( _face ) 1
+#endif
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT cffgload
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_get_glyph_data( TT_Face face,
+ FT_UInt glyph_index,
+ FT_Byte** pointer,
+ FT_ULong* length )
+ {
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* For incremental fonts get the character data using the */
+ /* callback function. */
+ if ( face->root.internal->incremental_interface )
+ {
+ FT_Data data;
+ FT_Error error =
+ face->root.internal->incremental_interface->funcs->get_glyph_data(
+ face->root.internal->incremental_interface->object,
+ glyph_index, &data );
+
+
+ *pointer = (FT_Byte*)data.pointer;
+ *length = data.length;
+
+ return error;
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ {
+ CFF_Font cff = (CFF_Font)( face->extra.data );
+
+
+ return cff_index_access_element( &cff->charstrings_index, glyph_index,
+ pointer, length );
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_free_glyph_data( TT_Face face,
+ FT_Byte** pointer,
+ FT_ULong length )
+ {
+#ifndef FT_CONFIG_OPTION_INCREMENTAL
+ FT_UNUSED( length );
+#endif
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* For incremental fonts get the character data using the */
+ /* callback function. */
+ if ( face->root.internal->incremental_interface )
+ {
+ FT_Data data;
+
+
+ data.pointer = *pointer;
+ data.length = (FT_UInt)length;
+
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object, &data );
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ {
+ CFF_Font cff = (CFF_Font)( face->extra.data );
+
+
+ cff_index_forget_element( &cff->charstrings_index, pointer );
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#if 0 /* unused until we support pure CFF fonts */
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_compute_max_advance( TT_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error = FT_Err_Ok;
+ CFF_Decoder decoder;
+ FT_Int glyph_index;
+ CFF_Font cff = (CFF_Font)face->other;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+ const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs;
+
+
+ *max_advance = 0;
+
+ /* Initialize load decoder */
+ decoder_funcs->init( &decoder, face, 0, 0, 0, 0, 0, 0 );
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ /* For each glyph, parse the glyph charstring and extract */
+ /* the advance width. */
+ for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+ glyph_index++ )
+ {
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ /* now get load the unscaled outline */
+ error = cff_get_glyph_data( face, glyph_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ error = decoder_funcs->prepare( &decoder, size, glyph_index );
+ if ( !error )
+ error = decoder_funcs->parse_charstrings_old( &decoder,
+ charstring,
+ charstring_len,
+ 0 );
+
+ cff_free_glyph_data( face, &charstring, &charstring_len );
+ }
+
+ /* ignore the error if one has occurred -- skip to next glyph */
+ error = FT_Err_Ok;
+ }
+
+ *max_advance = decoder.builder.advance.x;
+
+ return FT_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_slot_load( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ CFF_Decoder decoder;
+ PS_Decoder psdecoder;
+ TT_Face face = (TT_Face)glyph->root.face;
+ FT_Bool hinting, scaled, force_scaling;
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+ const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+
+ force_scaling = FALSE;
+
+ /* in a CID-keyed font, consider `glyph_index' as a CID and map */
+ /* it immediately to the real glyph_index -- if it isn't a */
+ /* subsetted font, glyph_indices and CIDs are identical, though */
+ if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
+ cff->charset.cids )
+ {
+ /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
+ if ( glyph_index != 0 )
+ {
+ glyph_index = cff_charset_cid_to_gindex( &cff->charset,
+ glyph_index );
+ if ( glyph_index == 0 )
+ return FT_THROW( Invalid_Argument );
+ }
+ }
+ else if ( glyph_index >= cff->num_glyphs )
+ return FT_THROW( Invalid_Argument );
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = 0x10000L;
+ glyph->y_scale = 0x10000L;
+ if ( size )
+ {
+ glyph->x_scale = size->root.metrics.x_scale;
+ glyph->y_scale = size->root.metrics.y_scale;
+ }
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* try to load embedded bitmap if any */
+ /* */
+ /* XXX: The convention should be emphasized in */
+ /* the documents because it can be confusing. */
+ if ( size )
+ {
+ CFF_Face cff_face = (CFF_Face)size->root.face;
+ SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt;
+ FT_Stream stream = cff_face->root.stream;
+
+
+ if ( size->strike_index != 0xFFFFFFFFUL &&
+ ( load_flags & FT_LOAD_NO_BITMAP ) == 0 &&
+ IS_DEFAULT_INSTANCE( size->root.face ) )
+ {
+ TT_SBit_MetricsRec metrics;
+
+
+ error = sfnt->load_sbit_image( face,
+ size->strike_index,
+ glyph_index,
+ (FT_UInt)load_flags,
+ stream,
+ &glyph->root.bitmap,
+ &metrics );
+
+ if ( !error )
+ {
+ FT_Bool has_vertical_info;
+ FT_UShort advance;
+ FT_Short dummy;
+
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ glyph->root.metrics.width = (FT_Pos)metrics.width * 64;
+ glyph->root.metrics.height = (FT_Pos)metrics.height * 64;
+
+ glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64;
+ glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64;
+ glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64;
+
+ glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64;
+ glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64;
+ glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64;
+
+ glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
+
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ glyph->root.bitmap_left = metrics.vertBearingX;
+ glyph->root.bitmap_top = metrics.vertBearingY;
+ }
+ else
+ {
+ glyph->root.bitmap_left = metrics.horiBearingX;
+ glyph->root.bitmap_top = metrics.horiBearingY;
+ }
+
+ /* compute linear advance widths */
+
+ (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
+ glyph_index,
+ &dummy,
+ &advance );
+ glyph->root.linearHoriAdvance = advance;
+
+ has_vertical_info = FT_BOOL(
+ face->vertical_info &&
+ face->vertical.number_Of_VMetrics > 0 );
+
+ /* get the vertical metrics from the vmtx table if we have one */
+ if ( has_vertical_info )
+ {
+ (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+ glyph_index,
+ &dummy,
+ &advance );
+ glyph->root.linearVertAdvance = advance;
+ }
+ else
+ {
+ /* make up vertical ones */
+ if ( face->os2.version != 0xFFFFU )
+ glyph->root.linearVertAdvance = (FT_Pos)
+ ( face->os2.sTypoAscender - face->os2.sTypoDescender );
+ else
+ glyph->root.linearVertAdvance = (FT_Pos)
+ ( face->horizontal.Ascender - face->horizontal.Descender );
+ }
+
+ return error;
+ }
+ }
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ /* return immediately if we only want the embedded bitmaps */
+ if ( load_flags & FT_LOAD_SBITS_ONLY )
+ return FT_THROW( Invalid_Argument );
+
+#ifdef FT_CONFIG_OPTION_SVG
+ /* check for OT-SVG */
+ if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+ {
+ /*
+ * We load the SVG document and try to grab the advances from the
+ * table. For the bearings we rely on the presetting hook to do that.
+ */
+
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ if ( size && (size->root.metrics.x_ppem < 1 ||
+ size->root.metrics.y_ppem < 1 ) )
+ {
+ error = FT_THROW( Invalid_Size_Handle );
+ return error;
+ }
+
+ FT_TRACE3(( "Trying to load SVG glyph\n" ));
+
+ error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index );
+ if ( !error )
+ {
+ FT_Fixed x_scale = size->root.metrics.x_scale;
+ FT_Fixed y_scale = size->root.metrics.y_scale;
+
+ FT_Short dummy;
+ FT_UShort advanceX;
+ FT_UShort advanceY;
+
+
+ FT_TRACE3(( "Successfully loaded SVG glyph\n" ));
+
+ glyph->root.format = FT_GLYPH_FORMAT_SVG;
+
+ /*
+ * If horizontal or vertical advances are not present in the table,
+ * this is a problem with the font since the standard requires them.
+ * However, we are graceful and calculate the values by ourselves
+ * for the vertical case.
+ */
+ sfnt->get_metrics( face,
+ FALSE,
+ glyph_index,
+ &dummy,
+ &advanceX );
+ sfnt->get_metrics( face,
+ TRUE,
+ glyph_index,
+ &dummy,
+ &advanceY );
+
+ glyph->root.linearHoriAdvance = advanceX;
+ glyph->root.linearVertAdvance = advanceY;
+
+ glyph->root.metrics.horiAdvance = FT_MulFix( advanceX, x_scale );
+ glyph->root.metrics.vertAdvance = FT_MulFix( advanceY, y_scale );
+
+ return error;
+ }
+
+ FT_TRACE3(( "Failed to load SVG glyph\n" ));
+ }
+
+#endif /* FT_CONFIG_OPTION_SVG */
+
+ /* if we have a CID subfont, use its matrix (which has already */
+ /* been multiplied with the root matrix) */
+
+ /* this scaling is only relevant if the PS hinter isn't active */
+ if ( cff->num_subfonts )
+ {
+ FT_Long top_upm, sub_upm;
+ FT_Byte fd_index = cff_fd_select_get( &cff->fd_select,
+ glyph_index );
+
+
+ if ( fd_index >= cff->num_subfonts )
+ fd_index = (FT_Byte)( cff->num_subfonts - 1 );
+
+ top_upm = (FT_Long)cff->top_font.font_dict.units_per_em;
+ sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em;
+
+ font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix;
+ font_offset = cff->subfonts[fd_index]->font_dict.font_offset;
+
+ if ( top_upm != sub_upm )
+ {
+ glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm );
+ glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm );
+
+ force_scaling = TRUE;
+ }
+ }
+ else
+ {
+ font_matrix = cff->top_font.font_dict.font_matrix;
+ font_offset = cff->top_font.font_dict.font_offset;
+ }
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ /* top-level code ensures that FT_LOAD_NO_HINTING is set */
+ /* if FT_LOAD_NO_SCALE is active */
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+ scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
+
+ glyph->hint = hinting;
+ glyph->scaled = scaled;
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
+
+ {
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face );
+#endif
+
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ decoder_funcs->init( &decoder, face, size, glyph, hinting,
+ FT_LOAD_TARGET_MODE( load_flags ),
+ cff_get_glyph_data,
+ cff_free_glyph_data );
+
+ /* this is for pure CFFs */
+ if ( load_flags & FT_LOAD_ADVANCE_ONLY )
+ decoder.width_only = TRUE;
+
+ decoder.builder.no_recurse =
+ FT_BOOL( load_flags & FT_LOAD_NO_RECURSE );
+
+ /* this function also checks for a valid subfont index */
+ error = decoder_funcs->prepare( &decoder, size, glyph_index );
+ if ( error )
+ goto Glyph_Build_Finished;
+
+ /* now load the unscaled outline */
+ error = cff_get_glyph_data( face, glyph_index,
+ &charstring, &charstring_len );
+ if ( error )
+ goto Glyph_Build_Finished;
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ /* choose which CFF renderer to use */
+ if ( driver->hinting_engine == FT_HINTING_FREETYPE )
+ error = decoder_funcs->parse_charstrings_old( &decoder,
+ charstring,
+ charstring_len,
+ 0 );
+ else
+#endif
+ {
+ psaux->ps_decoder_init( &psdecoder, &decoder, FALSE );
+
+ error = decoder_funcs->parse_charstrings( &psdecoder,
+ charstring,
+ charstring_len );
+
+ /* Adobe's engine uses 16.16 numbers everywhere; */
+ /* as a consequence, glyphs larger than 2000ppem get rejected */
+ if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
+ {
+ /* this time, we retry unhinted and scale up the glyph later on */
+ /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
+ /* 0x400 for both `x_scale' and `y_scale' in this case) */
+ hinting = FALSE;
+ force_scaling = TRUE;
+ glyph->hint = hinting;
+
+ error = decoder_funcs->parse_charstrings( &psdecoder,
+ charstring,
+ charstring_len );
+ }
+ }
+
+ cff_free_glyph_data( face, &charstring, charstring_len );
+
+ if ( error )
+ goto Glyph_Build_Finished;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* Control data and length may not be available for incremental */
+ /* fonts. */
+ if ( face->root.internal->incremental_interface )
+ {
+ glyph->root.control_data = NULL;
+ glyph->root.control_len = 0;
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ /* We set control_data and control_len if charstrings is loaded. */
+ /* See how charstring loads at cff_index_access_element() in */
+ /* cffload.c. */
+ {
+ CFF_Index csindex = &cff->charstrings_index;
+
+
+ if ( csindex->offsets )
+ {
+ glyph->root.control_data = csindex->bytes +
+ csindex->offsets[glyph_index] - 1;
+ glyph->root.control_len = (FT_Long)charstring_len;
+ }
+ }
+
+ Glyph_Build_Finished:
+ /* save new glyph tables, if no error */
+ if ( !error )
+ decoder.builder.funcs.done( &decoder.builder );
+ /* XXX: anything to do for broken glyph entry? */
+ }
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* Incremental fonts can optionally override the metrics. */
+ if ( !error &&
+ face->root.internal->incremental_interface &&
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+ {
+ FT_Incremental_MetricsRec metrics;
+
+
+ metrics.bearing_x = decoder.builder.left_bearing.x;
+ metrics.bearing_y = 0;
+ metrics.advance = decoder.builder.advance.x;
+ metrics.advance_v = decoder.builder.advance.y;
+
+ error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+ face->root.internal->incremental_interface->object,
+ glyph_index, FALSE, &metrics );
+
+ decoder.builder.left_bearing.x = metrics.bearing_x;
+ decoder.builder.advance.x = metrics.advance;
+ decoder.builder.advance.y = metrics.advance_v;
+ }
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ if ( !error )
+ {
+ /* Now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax. */
+
+ /* For composite glyphs, return only left side bearing and */
+ /* advance width. */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.glyph_width;
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+ FT_Bool has_vertical_info;
+
+
+ if ( face->horizontal.number_Of_HMetrics )
+ {
+ FT_Short horiBearingX = 0;
+ FT_UShort horiAdvance = 0;
+
+
+ ( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
+ glyph_index,
+ &horiBearingX,
+ &horiAdvance );
+ metrics->horiAdvance = horiAdvance;
+ metrics->horiBearingX = horiBearingX;
+ glyph->root.linearHoriAdvance = horiAdvance;
+ }
+ else
+ {
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.glyph_width;
+ glyph->root.linearHoriAdvance = decoder.glyph_width;
+ }
+
+ glyph->root.internal->glyph_transformed = 0;
+
+ has_vertical_info = FT_BOOL( face->vertical_info &&
+ face->vertical.number_Of_VMetrics > 0 );
+
+ /* get the vertical metrics from the vmtx table if we have one */
+ if ( has_vertical_info )
+ {
+ FT_Short vertBearingY = 0;
+ FT_UShort vertAdvance = 0;
+
+
+ ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+ glyph_index,
+ &vertBearingY,
+ &vertAdvance );
+ metrics->vertBearingY = vertBearingY;
+ metrics->vertAdvance = vertAdvance;
+ }
+ else
+ {
+ /* make up vertical ones */
+ if ( face->os2.version != 0xFFFFU )
+ metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender -
+ face->os2.sTypoDescender );
+ else
+ metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender -
+ face->horizontal.Descender );
+ }
+
+ glyph->root.linearVertAdvance = metrics->vertAdvance;
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ glyph->root.outline.flags = 0;
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+ /* apply the font matrix, if any */
+ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
+ font_matrix.xy != 0 || font_matrix.yx != 0 )
+ {
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
+ font_matrix.xx );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
+ font_matrix.yy );
+ }
+
+ if ( font_offset.x || font_offset.y )
+ {
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+ metrics->horiAdvance += font_offset.x;
+ metrics->vertAdvance += font_offset.y;
+ }
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = &glyph->root.outline;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ if ( !hinting || !decoder.builder.hints_funcs )
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+
+ if ( has_vertical_info )
+ {
+ metrics->vertBearingX = metrics->horiBearingX -
+ metrics->horiAdvance / 2;
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY,
+ glyph->y_scale );
+ }
+ else
+ {
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ ft_synthesize_vertical_metrics( metrics,
+ metrics->vertAdvance );
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffgload.h b/modules/freetype2/src/cff/cffgload.h
new file mode 100644
index 0000000000..3b8cf236dd
--- /dev/null
+++ b/modules/freetype2/src/cff/cffgload.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ *
+ * cffgload.h
+ *
+ * OpenType Glyph Loader (specification).
+ *
+ * Copyright (C) 1996-2023 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 CFFGLOAD_H_
+#define CFFGLOAD_H_
+
+
+#include <freetype/freetype.h>
+#include <freetype/internal/cffotypes.h>
+
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( FT_Error )
+ cff_get_glyph_data( TT_Face face,
+ FT_UInt glyph_index,
+ FT_Byte** pointer,
+ FT_ULong* length );
+ FT_LOCAL( void )
+ cff_free_glyph_data( TT_Face face,
+ FT_Byte** pointer,
+ FT_ULong length );
+
+
+#if 0 /* unused until we support pure CFF fonts */
+
+ /* Compute the maximum advance width of a font through quick parsing */
+ FT_LOCAL( FT_Error )
+ cff_compute_max_advance( TT_Face face,
+ FT_Int* max_advance );
+
+#endif /* 0 */
+
+
+ FT_LOCAL( FT_Error )
+ cff_slot_load( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* CFFGLOAD_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffload.c b/modules/freetype2/src/cff/cffload.c
new file mode 100644
index 0000000000..4b8c6e16c5
--- /dev/null
+++ b/modules/freetype2/src/cff/cffload.c
@@ -0,0 +1,2579 @@
+/****************************************************************************
+ *
+ * cffload.c
+ *
+ * OpenType and CFF data/program tables loader (body).
+ *
+ * Copyright (C) 1996-2023 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/tttags.h>
+#include <freetype/t1tables.h>
+#include <freetype/internal/psaux.h>
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include <freetype/ftmm.h>
+#include <freetype/internal/services/svmm.h>
+#endif
+
+#include "cffload.h"
+#include "cffparse.h"
+
+#include "cfferrs.h"
+
+
+#define FT_FIXED_ONE ( (FT_Fixed)0x10000 )
+
+
+#if 1
+
+ static const FT_UShort cff_isoadobe_charset[229] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228
+ };
+
+ static const FT_UShort cff_expert_charset[166] =
+ {
+ 0, 1, 229, 230, 231, 232, 233, 234,
+ 235, 236, 237, 238, 13, 14, 15, 99,
+ 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 27, 28, 249, 250, 251, 252,
+ 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 109, 110,
+ 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282,
+ 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306,
+ 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 158, 155, 163, 319,
+ 320, 321, 322, 323, 324, 325, 326, 150,
+ 164, 169, 327, 328, 329, 330, 331, 332,
+ 333, 334, 335, 336, 337, 338, 339, 340,
+ 341, 342, 343, 344, 345, 346, 347, 348,
+ 349, 350, 351, 352, 353, 354, 355, 356,
+ 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372,
+ 373, 374, 375, 376, 377, 378
+ };
+
+ static const FT_UShort cff_expertsubset_charset[87] =
+ {
+ 0, 1, 231, 232, 235, 236, 237, 238,
+ 13, 14, 15, 99, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 27, 28,
+ 249, 250, 251, 253, 254, 255, 256, 257,
+ 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 109, 110, 267, 268, 269, 270, 272,
+ 300, 301, 302, 305, 314, 315, 158, 155,
+ 163, 320, 321, 322, 323, 324, 325, 326,
+ 150, 164, 169, 327, 328, 329, 330, 331,
+ 332, 333, 334, 335, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 345, 346
+ };
+
+ static const FT_UShort cff_standard_encoding[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110,
+ 0, 111, 112, 113, 114, 0, 115, 116,
+ 117, 118, 119, 120, 121, 122, 0, 123,
+ 0, 124, 125, 126, 127, 128, 129, 130,
+ 131, 0, 132, 133, 0, 134, 135, 136,
+ 137, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 138, 0, 139, 0, 0, 0, 0,
+ 140, 141, 142, 143, 0, 0, 0, 0,
+ 0, 144, 0, 0, 0, 145, 0, 0,
+ 146, 147, 148, 149, 0, 0, 0, 0
+ };
+
+ static const FT_UShort cff_expert_encoding[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 229, 230, 0, 231, 232, 233, 234,
+ 235, 236, 237, 238, 13, 14, 15, 99,
+ 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 27, 28, 249, 250, 251, 252,
+ 0, 253, 254, 255, 256, 257, 0, 0,
+ 0, 258, 0, 0, 259, 260, 261, 262,
+ 0, 0, 263, 264, 265, 0, 266, 109,
+ 110, 267, 268, 269, 0, 270, 271, 272,
+ 273, 274, 275, 276, 277, 278, 279, 280,
+ 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 301, 302, 303, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 304, 305, 306, 0, 0, 307, 308,
+ 309, 310, 311, 0, 312, 0, 0, 312,
+ 0, 0, 314, 315, 0, 0, 316, 317,
+ 318, 0, 0, 0, 158, 155, 163, 319,
+ 320, 321, 322, 323, 324, 325, 0, 0,
+ 326, 150, 164, 169, 327, 328, 329, 330,
+ 331, 332, 333, 334, 335, 336, 337, 338,
+ 339, 340, 341, 342, 343, 344, 345, 346,
+ 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362,
+ 363, 364, 365, 366, 367, 368, 369, 370,
+ 371, 372, 373, 374, 375, 376, 377, 378
+ };
+
+#endif /* 1 */
+
+
+ FT_LOCAL_DEF( FT_UShort )
+ cff_get_standard_encoding( FT_UInt charcode )
+ {
+ return (FT_UShort)( charcode < 256 ? cff_standard_encoding[charcode]
+ : 0 );
+ }
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT cffload
+
+
+ /* read an offset from the index's stream current position */
+ static FT_ULong
+ cff_index_read_offset( CFF_Index idx,
+ FT_Error *errorp )
+ {
+ FT_Error error;
+ FT_Stream stream = idx->stream;
+ FT_Byte tmp[4];
+ FT_ULong result = 0;
+
+
+ if ( !FT_STREAM_READ( tmp, idx->off_size ) )
+ {
+ FT_Int nn;
+
+
+ for ( nn = 0; nn < idx->off_size; nn++ )
+ result = ( result << 8 ) | tmp[nn];
+ }
+
+ *errorp = error;
+ return result;
+ }
+
+
+ static FT_Error
+ cff_index_init( CFF_Index idx,
+ FT_Stream stream,
+ FT_Bool load,
+ FT_Bool cff2 )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_UInt count;
+
+
+ FT_ZERO( idx );
+
+ idx->stream = stream;
+ idx->start = FT_STREAM_POS();
+
+ if ( cff2 )
+ {
+ if ( FT_READ_ULONG( count ) )
+ goto Exit;
+ idx->hdr_size = 5;
+ }
+ else
+ {
+ if ( FT_READ_USHORT( count ) )
+ goto Exit;
+ idx->hdr_size = 3;
+ }
+
+ if ( count > 0 )
+ {
+ FT_Byte offsize;
+ FT_ULong size;
+
+
+ /* there is at least one element; read the offset size, */
+ /* then access the offset table to compute the index's total size */
+ if ( FT_READ_BYTE( offsize ) )
+ goto Exit;
+
+ if ( offsize < 1 || offsize > 4 )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ idx->count = count;
+ idx->off_size = offsize;
+ size = (FT_ULong)( count + 1 ) * offsize;
+
+ idx->data_offset = idx->start + idx->hdr_size + size;
+
+ if ( FT_STREAM_SKIP( size - offsize ) )
+ goto Exit;
+
+ size = cff_index_read_offset( idx, &error );
+ if ( error )
+ goto Exit;
+
+ if ( size == 0 )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ idx->data_size = --size;
+
+ if ( load )
+ {
+ /* load the data */
+ if ( FT_FRAME_EXTRACT( size, idx->bytes ) )
+ goto Exit;
+ }
+ else
+ {
+ /* skip the data */
+ if ( FT_STREAM_SKIP( size ) )
+ goto Exit;
+ }
+ }
+
+ Exit:
+ if ( error )
+ FT_FREE( idx->offsets );
+
+ return error;
+ }
+
+
+ static void
+ cff_index_done( CFF_Index idx )
+ {
+ if ( idx->stream )
+ {
+ FT_Stream stream = idx->stream;
+ FT_Memory memory = stream->memory;
+
+
+ if ( idx->bytes )
+ FT_FRAME_RELEASE( idx->bytes );
+
+ FT_FREE( idx->offsets );
+ FT_ZERO( idx );
+ }
+ }
+
+
+ static FT_Error
+ cff_index_load_offsets( CFF_Index idx )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Stream stream = idx->stream;
+ FT_Memory memory = stream->memory;
+
+
+ if ( idx->count > 0 && !idx->offsets )
+ {
+ FT_Byte offsize = idx->off_size;
+ FT_ULong data_size;
+ FT_Byte* p;
+ FT_Byte* p_end;
+ FT_ULong* poff;
+
+
+ data_size = (FT_ULong)( idx->count + 1 ) * offsize;
+
+ if ( FT_QNEW_ARRAY( idx->offsets, idx->count + 1 ) ||
+ FT_STREAM_SEEK( idx->start + idx->hdr_size ) ||
+ FT_FRAME_ENTER( data_size ) )
+ goto Exit;
+
+ poff = idx->offsets;
+ p = (FT_Byte*)stream->cursor;
+ p_end = p + data_size;
+
+ switch ( offsize )
+ {
+ case 1:
+ for ( ; p < p_end; p++, poff++ )
+ poff[0] = p[0];
+ break;
+
+ case 2:
+ for ( ; p < p_end; p += 2, poff++ )
+ poff[0] = FT_PEEK_USHORT( p );
+ break;
+
+ case 3:
+ for ( ; p < p_end; p += 3, poff++ )
+ poff[0] = FT_PEEK_UOFF3( p );
+ break;
+
+ default:
+ for ( ; p < p_end; p += 4, poff++ )
+ poff[0] = FT_PEEK_ULONG( p );
+ }
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ if ( error )
+ FT_FREE( idx->offsets );
+
+ return error;
+ }
+
+
+ /* Allocate a table containing pointers to an index's elements. */
+ /* The `pool' argument makes this function convert the index */
+ /* 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_ULong* pool_size )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = idx->stream->memory;
+
+ FT_Byte** tbl = NULL;
+ FT_Byte* new_bytes = NULL;
+ FT_ULong new_size;
+
+
+ *table = NULL;
+
+ if ( !idx->offsets )
+ {
+ error = cff_index_load_offsets( idx );
+ if ( error )
+ goto Exit;
+ }
+
+ new_size = idx->data_size + idx->count;
+
+ if ( idx->count > 0 &&
+ !FT_QNEW_ARRAY( tbl, idx->count + 1 ) &&
+ ( !pool || !FT_ALLOC( new_bytes, new_size ) ) )
+ {
+ 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 %ld set to zero\n",
+ cur_offset ));
+ cur_offset = 0;
+ }
+
+ if ( !pool )
+ tbl[0] = org_bytes + cur_offset;
+ else
+ tbl[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 )
+ tbl[n] = org_bytes + next_offset;
+ else
+ {
+ tbl[n] = new_bytes + next_offset + extra;
+
+ if ( next_offset != cur_offset )
+ {
+ FT_MEM_COPY( tbl[n - 1],
+ org_bytes + cur_offset,
+ tbl[n] - tbl[n - 1] );
+ tbl[n][0] = '\0';
+ tbl[n] += 1;
+ extra++;
+ }
+ }
+
+ cur_offset = next_offset;
+ }
+ *table = tbl;
+
+ if ( pool )
+ *pool = new_bytes;
+ if ( pool_size )
+ *pool_size = new_size;
+ }
+
+ Exit:
+ if ( error && new_bytes )
+ FT_FREE( new_bytes );
+ if ( error && tbl )
+ FT_FREE( tbl );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_index_access_element( CFF_Index idx,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( idx && idx->count > element )
+ {
+ /* compute start and end offsets */
+ FT_Stream stream = idx->stream;
+ FT_ULong off1, off2 = 0;
+
+
+ /* load offsets from file or the offset table */
+ if ( !idx->offsets )
+ {
+ FT_ULong pos = element * idx->off_size;
+
+
+ if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) )
+ goto Exit;
+
+ off1 = cff_index_read_offset( idx, &error );
+ if ( error )
+ goto Exit;
+
+ if ( off1 != 0 )
+ {
+ do
+ {
+ element++;
+ off2 = cff_index_read_offset( idx, &error );
+
+ } while ( off2 == 0 && element < idx->count );
+ }
+ }
+ else /* use offsets table */
+ {
+ off1 = idx->offsets[element];
+ if ( off1 )
+ {
+ do
+ {
+ element++;
+ off2 = idx->offsets[element];
+
+ } while ( off2 == 0 && element < idx->count );
+ }
+ }
+
+ /* XXX: should check off2 does not exceed the end of this entry; */
+ /* at present, only truncate off2 at the end of this stream */
+ if ( off2 > stream->size + 1 ||
+ idx->data_offset > stream->size - off2 + 1 )
+ {
+ FT_ERROR(( "cff_index_access_element:"
+ " offset to next entry (%ld)"
+ " exceeds the end of stream (%ld)\n",
+ off2, stream->size - idx->data_offset + 1 ));
+ off2 = stream->size - idx->data_offset + 1;
+ }
+
+ /* access element */
+ if ( off1 && off2 > off1 )
+ {
+ *pbyte_len = off2 - off1;
+
+ if ( idx->bytes )
+ {
+ /* this index was completely loaded in memory, that's easy */
+ *pbytes = idx->bytes + off1 - 1;
+ }
+ else
+ {
+ /* this index is still on disk/file, access it through a frame */
+ if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) ||
+ FT_FRAME_EXTRACT( off2 - off1, *pbytes ) )
+ goto Exit;
+ }
+ }
+ else
+ {
+ /* empty index element */
+ *pbytes = 0;
+ *pbyte_len = 0;
+ }
+ }
+ else
+ error = FT_THROW( Invalid_Argument );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_index_forget_element( CFF_Index idx,
+ FT_Byte** pbytes )
+ {
+ if ( idx->bytes == 0 )
+ {
+ FT_Stream stream = idx->stream;
+
+
+ FT_FRAME_RELEASE( *pbytes );
+ }
+ }
+
+
+ /* get an entry from Name INDEX */
+ FT_LOCAL_DEF( FT_String* )
+ cff_index_get_name( CFF_Font font,
+ FT_UInt element )
+ {
+ CFF_Index idx = &font->name_index;
+ FT_Memory memory;
+ FT_Byte* bytes;
+ FT_ULong byte_len;
+ FT_Error error;
+ FT_String* name = NULL;
+
+
+ if ( !idx->stream ) /* CFF2 does not include a name index */
+ goto Exit;
+
+ memory = idx->stream->memory;
+
+ error = cff_index_access_element( idx, element, &bytes, &byte_len );
+ if ( error )
+ goto Exit;
+
+ if ( !FT_QALLOC( name, byte_len + 1 ) )
+ {
+ FT_MEM_COPY( name, bytes, byte_len );
+ name[byte_len] = 0;
+ }
+ cff_index_forget_element( idx, &bytes );
+
+ Exit:
+ return name;
+ }
+
+
+ /* get an entry from String INDEX */
+ FT_LOCAL_DEF( FT_String* )
+ cff_index_get_string( CFF_Font font,
+ FT_UInt element )
+ {
+ return ( element < font->num_strings )
+ ? (FT_String*)font->strings[element]
+ : NULL;
+ }
+
+
+ FT_LOCAL_DEF( FT_String* )
+ cff_index_get_sid_string( CFF_Font font,
+ FT_UInt sid )
+ {
+ /* value 0xFFFFU indicates a missing dictionary entry */
+ if ( sid == 0xFFFFU )
+ return NULL;
+
+ /* if it is not a standard string, return it */
+ if ( sid > 390 )
+ return cff_index_get_string( font, sid - 391 );
+
+ /* CID-keyed CFF fonts don't have glyph names */
+ if ( !font->psnames )
+ return NULL;
+
+ /* this is a standard string */
+ return (FT_String *)font->psnames->adobe_std_strings( sid );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** FD Select table support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static void
+ CFF_Done_FD_Select( CFF_FDSelect fdselect,
+ FT_Stream stream )
+ {
+ if ( fdselect->data )
+ FT_FRAME_RELEASE( fdselect->data );
+
+ fdselect->data_size = 0;
+ fdselect->format = 0;
+ fdselect->range_count = 0;
+ }
+
+
+ static FT_Error
+ CFF_Load_FD_Select( CFF_FDSelect fdselect,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong offset )
+ {
+ FT_Error error;
+ FT_Byte format;
+ FT_UInt num_ranges;
+
+
+ /* read format */
+ if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) )
+ goto Exit;
+
+ fdselect->format = format;
+ fdselect->cache_count = 0; /* clear cache */
+
+ switch ( format )
+ {
+ case 0: /* format 0, that's simple */
+ fdselect->data_size = num_glyphs;
+ goto Load_Data;
+
+ case 3: /* format 3, a tad more complex */
+ if ( FT_READ_USHORT( num_ranges ) )
+ goto Exit;
+
+ if ( !num_ranges )
+ {
+ FT_TRACE0(( "CFF_Load_FD_Select: empty FDSelect array\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ fdselect->data_size = num_ranges * 3 + 2;
+
+ Load_Data:
+ if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) )
+ goto Exit;
+ break;
+
+ default: /* hmm... that's wrong */
+ error = FT_THROW( Invalid_File_Format );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Byte )
+ cff_fd_select_get( CFF_FDSelect fdselect,
+ FT_UInt glyph_index )
+ {
+ FT_Byte fd = 0;
+
+
+ /* if there is no FDSelect, return zero */
+ /* Note: CFF2 with just one Font Dict has no FDSelect */
+ if ( !fdselect->data )
+ goto Exit;
+
+ switch ( fdselect->format )
+ {
+ case 0:
+ fd = fdselect->data[glyph_index];
+ break;
+
+ case 3:
+ /* first, compare to the cache */
+ if ( glyph_index - fdselect->cache_first < fdselect->cache_count )
+ {
+ fd = fdselect->cache_fd;
+ break;
+ }
+
+ /* then, look up the ranges array */
+ {
+ FT_Byte* p = fdselect->data;
+ FT_Byte* p_limit = p + fdselect->data_size;
+ FT_Byte fd2;
+ FT_UInt first, limit;
+
+
+ first = FT_NEXT_USHORT( p );
+ do
+ {
+ if ( glyph_index < first )
+ break;
+
+ fd2 = *p++;
+ limit = FT_NEXT_USHORT( p );
+
+ if ( glyph_index < limit )
+ {
+ fd = fd2;
+
+ /* update cache */
+ fdselect->cache_first = first;
+ fdselect->cache_count = limit - first;
+ fdselect->cache_fd = fd2;
+ break;
+ }
+ first = limit;
+
+ } while ( p < p_limit );
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ Exit:
+ return fd;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** CFF font support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ cff_charset_compute_cids( CFF_Charset charset,
+ FT_UInt num_glyphs,
+ FT_Memory memory )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_UInt i;
+ FT_UShort max_cid = 0;
+
+
+ if ( charset->max_cid > 0 )
+ goto Exit;
+
+ for ( i = 0; i < num_glyphs; i++ )
+ {
+ if ( charset->sids[i] > max_cid )
+ max_cid = charset->sids[i];
+ }
+
+ if ( FT_NEW_ARRAY( charset->cids, (FT_ULong)max_cid + 1 ) )
+ goto Exit;
+
+ /* When multiple GIDs map to the same CID, we choose the lowest */
+ /* GID. This is not described in any spec, but it matches the */
+ /* behaviour of recent Acroread versions. The loop stops when */
+ /* the unsigned index wraps around after reaching zero. */
+ for ( i = num_glyphs - 1; i < num_glyphs; i-- )
+ charset->cids[charset->sids[i]] = (FT_UShort)i;
+
+ charset->max_cid = max_cid;
+ charset->num_glyphs = num_glyphs;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_UInt )
+ cff_charset_cid_to_gindex( CFF_Charset charset,
+ FT_UInt cid )
+ {
+ FT_UInt result = 0;
+
+
+ if ( cid <= charset->max_cid )
+ result = charset->cids[cid];
+
+ return result;
+ }
+
+
+ static void
+ cff_charset_free_cids( CFF_Charset charset,
+ FT_Memory memory )
+ {
+ FT_FREE( charset->cids );
+ charset->max_cid = 0;
+ }
+
+
+ static void
+ cff_charset_done( CFF_Charset charset,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ cff_charset_free_cids( charset, memory );
+
+ FT_FREE( charset->sids );
+ charset->format = 0;
+ charset->offset = 0;
+ }
+
+
+ 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 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_QNEW_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 -> %ld\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" ));
+ FT_ERROR(( "predefined charset (Adobe ISO-Latin)\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_QNEW_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" ));
+ FT_ERROR(( "predefined charset (Adobe Expert)\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_QNEW_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" ));
+ FT_ERROR(( "predefined charset (Adobe Expert Subset)\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_QNEW_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;
+ }
+
+ return error;
+ }
+
+
+ static void
+ cff_vstore_done( CFF_VStoreRec* vstore,
+ FT_Memory memory )
+ {
+ FT_UInt i;
+
+
+ /* free regionList and axisLists */
+ if ( vstore->varRegionList )
+ {
+ for ( i = 0; i < vstore->regionCount; i++ )
+ FT_FREE( vstore->varRegionList[i].axisList );
+ }
+ FT_FREE( vstore->varRegionList );
+
+ /* free varData and indices */
+ if ( vstore->varData )
+ {
+ for ( i = 0; i < vstore->dataCount; i++ )
+ FT_FREE( vstore->varData[i].regionIndices );
+ }
+ FT_FREE( vstore->varData );
+ }
+
+
+ /* convert 2.14 to Fixed */
+ #define FT_fdot14ToFixed( x ) ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
+
+
+ static FT_Error
+ cff_vstore_load( CFF_VStoreRec* vstore,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error = FT_ERR( Invalid_File_Format );
+
+ FT_ULong* dataOffsetArray = NULL;
+ FT_UInt i, j;
+
+
+ /* no offset means no vstore to parse */
+ if ( offset )
+ {
+ FT_UInt vsOffset;
+ FT_UInt format;
+ FT_UInt dataCount;
+ FT_UInt regionCount;
+ FT_ULong regionListOffset;
+
+
+ /* we need to parse the table to determine its size; */
+ /* skip table length */
+ if ( FT_STREAM_SEEK( base_offset + offset ) ||
+ FT_STREAM_SKIP( 2 ) )
+ goto Exit;
+
+ /* actual variation store begins after the length */
+ vsOffset = FT_STREAM_POS();
+
+ /* check the header */
+ if ( FT_READ_USHORT( format ) )
+ goto Exit;
+ if ( format != 1 )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* read top level fields */
+ if ( FT_READ_ULONG( regionListOffset ) ||
+ FT_READ_USHORT( dataCount ) )
+ goto Exit;
+
+ /* make temporary copy of item variation data offsets; */
+ /* we'll parse region list first, then come back */
+ if ( FT_QNEW_ARRAY( dataOffsetArray, dataCount ) )
+ goto Exit;
+
+ for ( i = 0; i < dataCount; i++ )
+ {
+ if ( FT_READ_ULONG( dataOffsetArray[i] ) )
+ goto Exit;
+ }
+
+ /* parse regionList and axisLists */
+ if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) ||
+ FT_READ_USHORT( vstore->axisCount ) ||
+ FT_READ_USHORT( regionCount ) )
+ goto Exit;
+
+ vstore->regionCount = 0;
+ if ( FT_QNEW_ARRAY( vstore->varRegionList, regionCount ) )
+ goto Exit;
+
+ for ( i = 0; i < regionCount; i++ )
+ {
+ CFF_VarRegion* region = &vstore->varRegionList[i];
+
+
+ if ( FT_QNEW_ARRAY( region->axisList, vstore->axisCount ) )
+ goto Exit;
+
+ /* keep track of how many axisList to deallocate on error */
+ vstore->regionCount++;
+
+ for ( j = 0; j < vstore->axisCount; j++ )
+ {
+ CFF_AxisCoords* axis = &region->axisList[j];
+
+ FT_Int16 start14, peak14, end14;
+
+
+ if ( FT_READ_SHORT( start14 ) ||
+ FT_READ_SHORT( peak14 ) ||
+ FT_READ_SHORT( end14 ) )
+ goto Exit;
+
+ axis->startCoord = FT_fdot14ToFixed( start14 );
+ axis->peakCoord = FT_fdot14ToFixed( peak14 );
+ axis->endCoord = FT_fdot14ToFixed( end14 );
+ }
+ }
+
+ /* use dataOffsetArray now to parse varData items */
+ vstore->dataCount = 0;
+ if ( FT_QNEW_ARRAY( vstore->varData, dataCount ) )
+ goto Exit;
+
+ for ( i = 0; i < dataCount; i++ )
+ {
+ CFF_VarData* data = &vstore->varData[i];
+
+
+ if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) )
+ goto Exit;
+
+ /* ignore `itemCount' and `shortDeltaCount' */
+ /* because CFF2 has no delta sets */
+ if ( FT_STREAM_SKIP( 4 ) )
+ goto Exit;
+
+ /* Note: just record values; consistency is checked later */
+ /* by cff_blend_build_vector when it consumes `vstore' */
+
+ if ( FT_READ_USHORT( data->regionIdxCount ) )
+ goto Exit;
+
+ if ( FT_QNEW_ARRAY( data->regionIndices, data->regionIdxCount ) )
+ goto Exit;
+
+ /* keep track of how many regionIndices to deallocate on error */
+ vstore->dataCount++;
+
+ for ( j = 0; j < data->regionIdxCount; j++ )
+ {
+ if ( FT_READ_USHORT( data->regionIndices[j] ) )
+ goto Exit;
+ }
+ }
+ }
+
+ error = FT_Err_Ok;
+
+ Exit:
+ FT_FREE( dataOffsetArray );
+ if ( error )
+ cff_vstore_done( vstore, memory );
+
+ return error;
+ }
+
+
+ /* Clear blend stack (after blend values are consumed). */
+ /* */
+ /* TODO: Should do this in cff_run_parse, but subFont */
+ /* ref is not available there. */
+ /* */
+ /* Allocation is not changed when stack is cleared. */
+ FT_LOCAL_DEF( void )
+ cff_blend_clear( CFF_SubFont subFont )
+ {
+ subFont->blend_top = subFont->blend_stack;
+ subFont->blend_used = 0;
+ }
+
+
+ /* Blend numOperands on the stack, */
+ /* store results into the first numBlends values, */
+ /* then pop remaining arguments. */
+ /* */
+ /* This is comparable to `cf2_doBlend' but */
+ /* the cffparse stack is different and can't be written. */
+ /* Blended values are written to a different buffer, */
+ /* using reserved operator 255. */
+ /* */
+ /* Blend calculation is done in 16.16 fixed-point. */
+ FT_LOCAL_DEF( FT_Error )
+ cff_blend_doBlend( CFF_SubFont subFont,
+ CFF_Parser parser,
+ FT_UInt numBlends )
+ {
+ FT_UInt delta;
+ FT_UInt base;
+ FT_UInt i, j;
+ FT_UInt size;
+
+ CFF_Blend blend = &subFont->blend;
+
+ FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */
+ FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
+
+ /* compute expected number of operands for this blend */
+ FT_UInt numOperands = (FT_UInt)( numBlends * blend->lenBV );
+ FT_UInt count = (FT_UInt)( parser->top - 1 - parser->stack );
+
+
+ if ( numOperands > count )
+ {
+ FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n",
+ count,
+ count == 1 ? "" : "s" ));
+
+ error = FT_THROW( Stack_Underflow );
+ goto Exit;
+ }
+
+ /* check whether we have room for `numBlends' values at `blend_top' */
+ size = 5 * numBlends; /* add 5 bytes per entry */
+ if ( subFont->blend_used + size > subFont->blend_alloc )
+ {
+ FT_Byte* blend_stack_old = subFont->blend_stack;
+ FT_Byte* blend_top_old = subFont->blend_top;
+
+
+ /* increase or allocate `blend_stack' and reset `blend_top'; */
+ /* prepare to append `numBlends' values to the buffer */
+ if ( FT_QREALLOC( subFont->blend_stack,
+ subFont->blend_alloc,
+ subFont->blend_alloc + size ) )
+ goto Exit;
+
+ subFont->blend_top = subFont->blend_stack + subFont->blend_used;
+ subFont->blend_alloc += size;
+
+ /* iterate over the parser stack and adjust pointers */
+ /* if the reallocated buffer has a different address */
+ if ( blend_stack_old &&
+ subFont->blend_stack != blend_stack_old )
+ {
+ FT_PtrDist offset = subFont->blend_stack - blend_stack_old;
+ FT_Byte** p;
+
+
+ for ( p = parser->stack; p < parser->top; p++ )
+ {
+ if ( *p >= blend_stack_old && *p < blend_top_old )
+ *p += offset;
+ }
+ }
+ }
+ subFont->blend_used += size;
+
+ base = count - numOperands; /* index of first blend arg */
+ delta = base + numBlends; /* index of first delta arg */
+
+ for ( i = 0; i < numBlends; i++ )
+ {
+ const FT_Int32* weight = &blend->BV[1];
+ FT_UInt32 sum;
+
+
+ /* convert inputs to 16.16 fixed-point */
+ sum = cff_parse_num( parser, &parser->stack[i + base] ) * 0x10000;
+
+ for ( j = 1; j < blend->lenBV; j++ )
+ sum += cff_parse_num( parser, &parser->stack[delta++] ) * *weight++;
+
+ /* point parser stack to new value on blend_stack */
+ parser->stack[i + base] = subFont->blend_top;
+
+ /* Push blended result as Type 2 5-byte fixed-point number. This */
+ /* will not conflict with actual DICTs because 255 is a reserved */
+ /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */
+ /* decode of this, which rounds to an integer. */
+ *subFont->blend_top++ = 255;
+ *subFont->blend_top++ = (FT_Byte)( sum >> 24 );
+ *subFont->blend_top++ = (FT_Byte)( sum >> 16 );
+ *subFont->blend_top++ = (FT_Byte)( sum >> 8 );
+ *subFont->blend_top++ = (FT_Byte)sum;
+ }
+
+ /* leave only numBlends results on parser stack */
+ parser->top = &parser->stack[base + numBlends];
+
+ Exit:
+ return error;
+ }
+
+
+ /* Compute a blend vector from variation store index and normalized */
+ /* vector based on pseudo-code in OpenType Font Variations Overview. */
+ /* */
+ /* Note: lenNDV == 0 produces a default blend vector, (1,0,0,...). */
+ FT_LOCAL_DEF( FT_Error )
+ cff_blend_build_vector( CFF_Blend blend,
+ FT_UInt vsindex,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV )
+ {
+ FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
+ FT_Memory memory = blend->font->memory; /* for FT_REALLOC */
+
+ FT_UInt len;
+ CFF_VStore vs;
+ CFF_VarData* varData;
+ FT_UInt master;
+
+
+ /* protect against malformed fonts */
+ if ( !( lenNDV == 0 || NDV ) )
+ {
+ FT_TRACE4(( " cff_blend_build_vector:"
+ " Malformed Normalize Design Vector data\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ blend->builtBV = FALSE;
+
+ vs = &blend->font->vstore;
+
+ /* VStore and fvar must be consistent */
+ if ( lenNDV != 0 && lenNDV != vs->axisCount )
+ {
+ FT_TRACE4(( " cff_blend_build_vector: Axis count mismatch\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( vsindex >= vs->dataCount )
+ {
+ FT_TRACE4(( " cff_blend_build_vector: vsindex out of range\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* select the item variation data structure */
+ varData = &vs->varData[vsindex];
+
+ /* prepare buffer for the blend vector */
+ len = varData->regionIdxCount + 1; /* add 1 for default component */
+ if ( FT_QRENEW_ARRAY( blend->BV, blend->lenBV, len ) )
+ goto Exit;
+
+ blend->lenBV = len;
+
+ /* outer loop steps through master designs to be blended */
+ for ( master = 0; master < len; master++ )
+ {
+ FT_UInt j;
+ FT_UInt idx;
+ CFF_VarRegion* varRegion;
+
+
+ /* default factor is always one */
+ if ( master == 0 )
+ {
+ blend->BV[master] = FT_FIXED_ONE;
+ FT_TRACE4(( " build blend vector len %d\n", len ));
+ FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 ));
+ continue;
+ }
+
+ /* VStore array does not include default master, so subtract one */
+ idx = varData->regionIndices[master - 1];
+ varRegion = &vs->varRegionList[idx];
+
+ if ( idx >= vs->regionCount )
+ {
+ FT_TRACE4(( " cff_blend_build_vector:"
+ " region index out of range\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Note: `lenNDV' could be zero. */
+ /* In that case, build default blend vector (1,0,0...). */
+ if ( !lenNDV )
+ {
+ blend->BV[master] = 0;
+ continue;
+ }
+
+ /* In the normal case, initialize each component to 1 */
+ /* before inner loop. */
+ blend->BV[master] = FT_FIXED_ONE; /* default */
+
+ /* inner loop steps through axes in this region */
+ for ( j = 0; j < lenNDV; j++ )
+ {
+ CFF_AxisCoords* axis = &varRegion->axisList[j];
+ FT_Fixed axisScalar;
+
+
+ /* compute the scalar contribution of this axis; */
+ /* ignore invalid ranges */
+ if ( axis->startCoord > axis->peakCoord ||
+ axis->peakCoord > axis->endCoord )
+ axisScalar = FT_FIXED_ONE;
+
+ else if ( axis->startCoord < 0 &&
+ axis->endCoord > 0 &&
+ axis->peakCoord != 0 )
+ axisScalar = FT_FIXED_ONE;
+
+ /* peak of 0 means ignore this axis */
+ else if ( axis->peakCoord == 0 )
+ axisScalar = FT_FIXED_ONE;
+
+ /* ignore this region if coords are out of range */
+ else if ( NDV[j] < axis->startCoord ||
+ NDV[j] > axis->endCoord )
+ axisScalar = 0;
+
+ /* calculate a proportional factor */
+ else
+ {
+ if ( NDV[j] == axis->peakCoord )
+ axisScalar = FT_FIXED_ONE;
+ else if ( NDV[j] < axis->peakCoord )
+ axisScalar = FT_DivFix( NDV[j] - axis->startCoord,
+ axis->peakCoord - axis->startCoord );
+ else
+ axisScalar = FT_DivFix( axis->endCoord - NDV[j],
+ axis->endCoord - axis->peakCoord );
+ }
+
+ /* take product of all the axis scalars */
+ blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar );
+ }
+
+ FT_TRACE4(( ", %f ",
+ blend->BV[master] / 65536.0 ));
+ }
+
+ FT_TRACE4(( "]\n" ));
+
+ /* record the parameters used to build the blend vector */
+ blend->lastVsindex = vsindex;
+
+ if ( lenNDV != 0 )
+ {
+ /* user has set a normalized vector */
+ if ( FT_QRENEW_ARRAY( blend->lastNDV, blend->lenNDV, lenNDV ) )
+ goto Exit;
+
+ FT_MEM_COPY( blend->lastNDV,
+ NDV,
+ lenNDV * sizeof ( *NDV ) );
+ }
+
+ blend->lenNDV = lenNDV;
+ blend->builtBV = TRUE;
+
+ Exit:
+ return error;
+ }
+
+
+ /* `lenNDV' is zero for default vector; */
+ /* return TRUE if blend vector needs to be built. */
+ FT_LOCAL_DEF( FT_Bool )
+ cff_blend_check_vector( CFF_Blend blend,
+ FT_UInt vsindex,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV )
+ {
+ if ( !blend->builtBV ||
+ blend->lastVsindex != vsindex ||
+ blend->lenNDV != lenNDV ||
+ ( lenNDV &&
+ ft_memcmp( NDV,
+ blend->lastNDV,
+ lenNDV * sizeof ( *NDV ) ) != 0 ) )
+ {
+ /* need to build blend vector */
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_get_var_blend( CFF_Face face,
+ FT_UInt *num_coords,
+ FT_Fixed* *coords,
+ FT_Fixed* *normalizedcoords,
+ FT_MM_Var* *mm_var )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ return mm->get_var_blend( FT_FACE( face ),
+ num_coords,
+ coords,
+ normalizedcoords,
+ mm_var );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_done_blend( CFF_Face face )
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+
+
+ if (mm)
+ mm->done_blend( FT_FACE( face ) );
+ }
+
+#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
+
+
+ static void
+ cff_encoding_done( CFF_Encoding encoding )
+ {
+ encoding->format = 0;
+ encoding->offset = 0;
+ encoding->count = 0;
+ }
+
+
+ static FT_Error
+ cff_encoding_load( CFF_Encoding encoding,
+ CFF_Charset charset,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_UInt count;
+ FT_UInt j;
+ FT_UShort glyph_sid;
+ FT_UInt glyph_code;
+
+
+ /* Check for charset->sids. If we do not have this, we fail. */
+ if ( !charset->sids )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Zero out the code to gid/sid mappings. */
+ for ( j = 0; j < 256; j++ )
+ {
+ encoding->sids [j] = 0;
+ encoding->codes[j] = 0;
+ }
+
+ /* Note: The encoding table in a CFF font is indexed by glyph index; */
+ /* the first encoded glyph index is 1. Hence, we read the character */
+ /* code (`glyph_code') at index j and make the assignment: */
+ /* */
+ /* encoding->codes[glyph_code] = j + 1 */
+ /* */
+ /* We also make the assignment: */
+ /* */
+ /* encoding->sids[glyph_code] = charset->sids[j + 1] */
+ /* */
+ /* This gives us both a code to GID and a code to SID mapping. */
+
+ if ( offset > 1 )
+ {
+ encoding->offset = base_offset + offset;
+
+ /* we need to parse the table to determine its size */
+ if ( FT_STREAM_SEEK( encoding->offset ) ||
+ FT_READ_BYTE( encoding->format ) ||
+ FT_READ_BYTE( count ) )
+ goto Exit;
+
+ switch ( encoding->format & 0x7F )
+ {
+ case 0:
+ {
+ FT_Byte* p;
+
+
+ /* By convention, GID 0 is always ".notdef" and is never */
+ /* coded in the font. Hence, the number of codes found */
+ /* in the table is `count+1'. */
+ /* */
+ encoding->count = count + 1;
+
+ if ( FT_FRAME_ENTER( count ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+
+ for ( j = 1; j <= count; j++ )
+ {
+ glyph_code = *p++;
+
+ /* Make sure j is not too big. */
+ if ( j < num_glyphs )
+ {
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)j;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[j];
+ }
+ }
+
+ FT_FRAME_EXIT();
+ }
+ break;
+
+ case 1:
+ {
+ FT_UInt nleft;
+ FT_UInt i = 1;
+ FT_UInt k;
+
+
+ encoding->count = 0;
+
+ /* Parse the Format1 ranges. */
+ for ( j = 0; j < count; j++, i += nleft )
+ {
+ /* Read the first glyph code of the range. */
+ if ( FT_READ_BYTE( glyph_code ) )
+ goto Exit;
+
+ /* Read the number of codes in the range. */
+ if ( FT_READ_BYTE( nleft ) )
+ goto Exit;
+
+ /* Increment nleft, so we read `nleft + 1' codes/sids. */
+ nleft++;
+
+ /* compute max number of character codes */
+ if ( (FT_UInt)nleft > encoding->count )
+ encoding->count = nleft;
+
+ /* Fill in the range of codes/sids. */
+ for ( k = i; k < nleft + i; k++, glyph_code++ )
+ {
+ /* Make sure k is not too big. */
+ if ( k < num_glyphs && glyph_code < 256 )
+ {
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)k;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[k];
+ }
+ }
+ }
+
+ /* simple check; one never knows what can be found in a font */
+ if ( encoding->count > 256 )
+ encoding->count = 256;
+ }
+ break;
+
+ default:
+ FT_ERROR(( "cff_encoding_load: invalid table format\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* Parse supplemental encodings, if any. */
+ if ( encoding->format & 0x80 )
+ {
+ FT_UInt gindex;
+
+
+ /* count supplements */
+ if ( FT_READ_BYTE( count ) )
+ goto Exit;
+
+ for ( j = 0; j < count; j++ )
+ {
+ /* Read supplemental glyph code. */
+ if ( FT_READ_BYTE( glyph_code ) )
+ goto Exit;
+
+ /* Read the SID associated with this glyph code. */
+ if ( FT_READ_USHORT( glyph_sid ) )
+ goto Exit;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = glyph_sid;
+
+ /* First, look up GID which has been assigned to */
+ /* SID glyph_sid. */
+ for ( gindex = 0; gindex < num_glyphs; gindex++ )
+ {
+ if ( charset->sids[gindex] == glyph_sid )
+ {
+ encoding->codes[glyph_code] = (FT_UShort)gindex;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* We take into account the fact a CFF font can use a predefined */
+ /* encoding without containing all of the glyphs encoded by this */
+ /* encoding (see the note at the end of section 12 in the CFF */
+ /* specification). */
+
+ switch ( (FT_UInt)offset )
+ {
+ case 0:
+ /* First, copy the code to SID mapping. */
+ FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 );
+ goto Populate;
+
+ case 1:
+ /* First, copy the code to SID mapping. */
+ FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 );
+
+ Populate:
+ /* Construct code to GID mapping from code to SID mapping */
+ /* and charset. */
+
+ encoding->offset = offset; /* used in cff_face_init */
+ encoding->count = 0;
+
+ error = cff_charset_compute_cids( charset, num_glyphs,
+ stream->memory );
+ if ( error )
+ goto Exit;
+
+ for ( j = 0; j < 256; j++ )
+ {
+ FT_UInt sid = encoding->sids[j];
+ FT_UInt gid = 0;
+
+
+ if ( sid )
+ gid = cff_charset_cid_to_gindex( charset, sid );
+
+ if ( gid != 0 )
+ {
+ encoding->codes[j] = (FT_UShort)gid;
+ encoding->count = j + 1;
+ }
+ else
+ {
+ encoding->codes[j] = 0;
+ encoding->sids [j] = 0;
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "cff_encoding_load: invalid table format\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+ }
+
+ Exit:
+
+ /* Clean up if there was an error. */
+ return error;
+ }
+
+
+ /* Parse private dictionary; first call is always from `cff_face_init', */
+ /* so NDV has not been set for CFF2 variation. */
+ /* */
+ /* `cff_slot_load' must call this function each time NDV changes. */
+ FT_LOCAL_DEF( FT_Error )
+ cff_load_private_dict( CFF_Font font,
+ CFF_SubFont subfont,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV )
+ {
+ FT_Error error = FT_Err_Ok;
+ CFF_ParserRec parser;
+ CFF_FontRecDict top = &subfont->font_dict;
+ CFF_Private priv = &subfont->private_dict;
+ FT_Stream stream = font->stream;
+ FT_UInt stackSize;
+
+
+ /* store handle needed to access memory, vstore for blend; */
+ /* we need this for clean-up even if there is no private DICT */
+ subfont->blend.font = font;
+ subfont->blend.usedBV = FALSE; /* clear state */
+
+ if ( !top->private_offset || !top->private_size )
+ goto Exit2; /* no private DICT, do nothing */
+
+ /* set defaults */
+ FT_ZERO( priv );
+
+ priv->blue_shift = 7;
+ priv->blue_fuzz = 1;
+ priv->lenIV = -1;
+ priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
+ priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
+
+ /* provide inputs for blend calculations */
+ priv->subfont = subfont;
+ subfont->lenNDV = lenNDV;
+ subfont->NDV = NDV;
+
+ /* add 1 for the operator */
+ stackSize = font->cff2 ? font->top_font.font_dict.maxstack + 1
+ : CFF_MAX_STACK_DEPTH + 1;
+
+ if ( cff_parser_init( &parser,
+ font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
+ priv,
+ font->library,
+ stackSize,
+ top->num_designs,
+ top->num_axes ) )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) ||
+ FT_FRAME_ENTER( top->private_size ) )
+ goto Exit;
+
+ FT_TRACE4(( " private dictionary:\n" ));
+ error = cff_parser_run( &parser,
+ (FT_Byte*)stream->cursor,
+ (FT_Byte*)stream->limit );
+ FT_FRAME_EXIT();
+
+ if ( error )
+ goto Exit;
+
+ /* ensure that `num_blue_values' is even */
+ priv->num_blue_values &= ~1;
+
+ /* sanitize `initialRandomSeed' to be a positive value, if necessary; */
+ /* this is not mandated by the specification but by our implementation */
+ if ( priv->initial_random_seed < 0 )
+ priv->initial_random_seed = -priv->initial_random_seed;
+ else if ( priv->initial_random_seed == 0 )
+ priv->initial_random_seed = 987654321;
+
+ /* some sanitizing to avoid overflows later on; */
+ /* the upper limits are ad-hoc values */
+ if ( priv->blue_shift > 1000 || priv->blue_shift < 0 )
+ {
+ FT_TRACE2(( "cff_load_private_dict:"
+ " setting unlikely BlueShift value %ld to default (7)\n",
+ priv->blue_shift ));
+ priv->blue_shift = 7;
+ }
+
+ if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 )
+ {
+ FT_TRACE2(( "cff_load_private_dict:"
+ " setting unlikely BlueFuzz value %ld to default (1)\n",
+ priv->blue_fuzz ));
+ priv->blue_fuzz = 1;
+ }
+
+ Exit:
+ /* clean up */
+ cff_blend_clear( subfont ); /* clear blend stack */
+ cff_parser_done( &parser ); /* free parser stack */
+
+ Exit2:
+ /* no clean up (parser not initialized) */
+ return error;
+ }
+
+
+ /* There are 3 ways to call this function, distinguished by code. */
+ /* */
+ /* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */
+ /* . CFF2_CODE_TOPDICT for CFF2 Top DICT */
+ /* . CFF2_CODE_FONTDICT for CFF2 Font DICT */
+
+ static FT_Error
+ cff_subfont_load( CFF_SubFont subfont,
+ CFF_Index idx,
+ FT_UInt font_index,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_UInt code,
+ CFF_Font font,
+ CFF_Face face )
+ {
+ FT_Error error;
+ CFF_ParserRec parser;
+ FT_Byte* dict = NULL;
+ FT_ULong dict_len;
+ CFF_FontRecDict top = &subfont->font_dict;
+ CFF_Private priv = &subfont->private_dict;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+ FT_Bool cff2 = FT_BOOL( code == CFF2_CODE_TOPDICT ||
+ code == CFF2_CODE_FONTDICT );
+ FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK
+ : CFF_MAX_STACK_DEPTH;
+
+
+ /* Note: We use default stack size for CFF2 Font DICT because */
+ /* Top and Font DICTs are not allowed to have blend operators. */
+ error = cff_parser_init( &parser,
+ code,
+ &subfont->font_dict,
+ font->library,
+ stackSize,
+ 0,
+ 0 );
+ if ( error )
+ goto Exit;
+
+ /* set defaults */
+ FT_ZERO( top );
+
+ top->underline_position = -( 100L << 16 );
+ top->underline_thickness = 50L << 16;
+ top->charstring_type = 2;
+ top->font_matrix.xx = 0x10000L;
+ top->font_matrix.yy = 0x10000L;
+ top->cid_count = 8720;
+
+ /* we use the implementation specific SID value 0xFFFF to indicate */
+ /* missing entries */
+ top->version = 0xFFFFU;
+ top->notice = 0xFFFFU;
+ top->copyright = 0xFFFFU;
+ top->full_name = 0xFFFFU;
+ top->family_name = 0xFFFFU;
+ top->weight = 0xFFFFU;
+ top->embedded_postscript = 0xFFFFU;
+
+ top->cid_registry = 0xFFFFU;
+ top->cid_ordering = 0xFFFFU;
+ top->cid_font_name = 0xFFFFU;
+
+ /* set default stack size */
+ top->maxstack = cff2 ? CFF2_DEFAULT_STACK : 48;
+
+ if ( idx->count ) /* count is nonzero for a real index */
+ error = cff_index_access_element( idx, font_index, &dict, &dict_len );
+ else
+ {
+ /* CFF2 has a fake top dict index; */
+ /* simulate `cff_index_access_element' */
+
+ /* Note: macros implicitly use `stream' and set `error' */
+ if ( FT_STREAM_SEEK( idx->data_offset ) ||
+ FT_FRAME_EXTRACT( idx->data_size, dict ) )
+ goto Exit;
+
+ dict_len = idx->data_size;
+ }
+
+ if ( !error )
+ {
+ FT_TRACE4(( " top dictionary:\n" ));
+ error = cff_parser_run( &parser, dict, FT_OFFSET( dict, dict_len ) );
+ }
+
+ /* clean up regardless of error */
+ if ( idx->count )
+ cff_index_forget_element( idx, &dict );
+ else
+ FT_FRAME_RELEASE( dict );
+
+ if ( error )
+ goto Exit;
+
+ /* if it is a CID font, we stop there */
+ if ( top->cid_registry != 0xFFFFU )
+ goto Exit;
+
+ /* Parse the private dictionary, if any. */
+ /* */
+ /* CFF2 does not have a private dictionary in the Top DICT */
+ /* but may have one in a Font DICT. We need to parse */
+ /* the latter here in order to load any local subrs. */
+ error = cff_load_private_dict( font, subfont, 0, 0 );
+ if ( error )
+ goto Exit;
+
+ if ( !cff2 )
+ {
+ /*
+ * Initialize the random number generator.
+ *
+ * - If we have a face-specific seed, use it.
+ * If non-zero, update it to a positive value.
+ *
+ * - Otherwise, use the seed from the CFF driver.
+ * If non-zero, update it to a positive value.
+ *
+ * - If the random value is zero, use the seed given by the subfont's
+ * `initialRandomSeed' value.
+ *
+ */
+ if ( face->root.internal->random_seed == -1 )
+ {
+ PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face );
+
+
+ subfont->random = (FT_UInt32)driver->random_seed;
+ if ( driver->random_seed )
+ {
+ do
+ {
+ driver->random_seed =
+ (FT_Int32)psaux->cff_random( (FT_UInt32)driver->random_seed );
+
+ } while ( driver->random_seed < 0 );
+ }
+ }
+ else
+ {
+ subfont->random = (FT_UInt32)face->root.internal->random_seed;
+ if ( face->root.internal->random_seed )
+ {
+ do
+ {
+ face->root.internal->random_seed =
+ (FT_Int32)psaux->cff_random(
+ (FT_UInt32)face->root.internal->random_seed );
+
+ } while ( face->root.internal->random_seed < 0 );
+ }
+ }
+
+ if ( !subfont->random )
+ subfont->random = (FT_UInt32)priv->initial_random_seed;
+ }
+
+ /* read the local subrs, if any */
+ if ( priv->local_subrs_offset )
+ {
+ if ( FT_STREAM_SEEK( base_offset + top->private_offset +
+ priv->local_subrs_offset ) )
+ goto Exit;
+
+ error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 );
+ if ( error )
+ goto Exit;
+
+ error = cff_index_get_pointers( &subfont->local_subrs_index,
+ &subfont->local_subrs, NULL, NULL );
+ if ( error )
+ goto Exit;
+ }
+
+ Exit:
+ cff_parser_done( &parser ); /* free parser stack */
+
+ return error;
+ }
+
+
+ static void
+ cff_subfont_done( FT_Memory memory,
+ CFF_SubFont subfont )
+ {
+ if ( subfont )
+ {
+ cff_index_done( &subfont->local_subrs_index );
+ FT_FREE( subfont->local_subrs );
+
+ FT_FREE( subfont->blend.lastNDV );
+ FT_FREE( subfont->blend.BV );
+ FT_FREE( subfont->blend_stack );
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_font_load( FT_Library library,
+ FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font font,
+ CFF_Face face,
+ FT_Bool pure_cff,
+ FT_Bool cff2 )
+ {
+ static const FT_Frame_Field cff_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRec
+
+ FT_FRAME_START( 3 ),
+ FT_FRAME_BYTE( version_major ),
+ FT_FRAME_BYTE( version_minor ),
+ FT_FRAME_BYTE( header_size ),
+ 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 );
+
+ dict = &font->top_font.font_dict;
+ base_offset = FT_STREAM_POS();
+
+ font->library = library;
+ font->stream = stream;
+ font->memory = memory;
+ font->cff2 = cff2;
+ font->base_offset = base_offset;
+
+ /* read CFF font header */
+ if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
+ goto Exit;
+
+ if ( cff2 )
+ {
+ if ( font->version_major != 2 ||
+ font->header_size < 5 )
+ {
+ FT_TRACE2(( " not a CFF2 font header\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
+ if ( FT_READ_USHORT( font->top_dict_length ) )
+ goto Exit;
+ }
+ else
+ {
+ FT_Byte absolute_offset;
+
+
+ if ( FT_READ_BYTE( absolute_offset ) )
+ goto Exit;
+
+ if ( font->version_major != 1 ||
+ font->header_size < 4 ||
+ absolute_offset > 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_SEEK( base_offset + font->header_size ) )
+ {
+ /* For pure CFFs we have read only four bytes so far. Contrary to */
+ /* other formats like SFNT those bytes doesn't define a signature; */
+ /* it is thus possible that the font isn't a CFF at all. */
+ if ( pure_cff )
+ {
+ FT_TRACE2(( " not a CFF file\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ }
+ goto Exit;
+ }
+
+ if ( cff2 )
+ {
+ /* For CFF2, the top dict data immediately follow the header */
+ /* and the length is stored in the header `offSize' field; */
+ /* there is no index for it. */
+ /* */
+ /* Use the `font_dict_index' to save the current position */
+ /* and length of data, but leave count at zero as an indicator. */
+ FT_ZERO( &font->font_dict_index );
+
+ font->font_dict_index.data_offset = FT_STREAM_POS();
+ font->font_dict_index.data_size = font->top_dict_length;
+
+ /* skip the top dict data for now, we will parse it later */
+ if ( FT_STREAM_SKIP( font->top_dict_length ) )
+ goto Exit;
+
+ /* next, read the global subrs index */
+ if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
+ stream, 1, cff2 ) ) )
+ goto Exit;
+ }
+ else
+ {
+ /* for CFF, read the name, top dict, string and global subrs index */
+ if ( FT_SET_ERROR( cff_index_init( &font->name_index,
+ stream, 0, cff2 ) ) )
+ {
+ if ( pure_cff )
+ {
+ FT_TRACE2(( " not a CFF file\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ }
+ goto Exit;
+ }
+
+ /* if we have an empty font name, */
+ /* it must be the only font in the CFF */
+ if ( font->name_index.count > 1 &&
+ font->name_index.data_size < font->name_index.count )
+ {
+ /* for pure CFFs, we still haven't checked enough bytes */
+ /* to be sure that it is a CFF at all */
+ error = pure_cff ? FT_THROW( Unknown_File_Format )
+ : FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( FT_SET_ERROR( cff_index_init( &font->font_dict_index,
+ stream, 0, cff2 ) ) ||
+ FT_SET_ERROR( cff_index_init( &string_index,
+ stream, 1, cff2 ) ) ||
+ FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
+ stream, 1, cff2 ) ) ||
+ FT_SET_ERROR( cff_index_get_pointers( &string_index,
+ &font->strings,
+ &font->string_pool,
+ &font->string_pool_size ) ) )
+ goto Exit;
+
+ /* there must be a Top DICT index entry for each name index entry */
+ if ( font->name_index.count > font->font_dict_index.count )
+ {
+ FT_ERROR(( "cff_font_load:"
+ " not enough entries in Top DICT index\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ 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" ));
+ FT_ERROR(( " "
+ " 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,
+ cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
+ font,
+ face );
+ if ( error )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
+ goto Exit;
+
+ error = cff_index_init( &font->charstrings_index, stream, 0, cff2 );
+ if ( error )
+ goto Exit;
+
+ /* now, check for a CID or CFF2 font */
+ if ( dict->cid_registry != 0xFFFFU ||
+ cff2 )
+ {
+ CFF_IndexRec fd_index;
+ CFF_SubFont sub = NULL;
+ FT_UInt idx;
+
+
+ /* for CFF2, read the Variation Store if available; */
+ /* this must follow the Top DICT parse and precede any Private DICT */
+ error = cff_vstore_load( &font->vstore,
+ stream,
+ base_offset,
+ dict->vstore_offset );
+ if ( error )
+ goto Exit;
+
+ /* 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, cff2 );
+ if ( error )
+ goto Exit;
+
+ /* Font Dicts are not limited to 256 for CFF2. */
+ /* TODO: support this for CFF2 */
+ 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,
+ cff2 ? CFF2_CODE_FONTDICT
+ : CFF_CODE_TOPDICT,
+ font,
+ face );
+ if ( error )
+ goto Fail_CID;
+ }
+
+ /* now load the FD Select array; */
+ /* CFF2 omits FDSelect if there is only one FD */
+ if ( !cff2 || fd_index.count > 1 )
+ 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, NULL );
+
+ if ( error )
+ goto Exit;
+
+ /* read the Charset and Encoding tables if available */
+ if ( !cff2 && 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;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_font_done( CFF_Font font )
+ {
+ FT_Memory memory = font->memory;
+ FT_UInt idx;
+
+
+ cff_index_done( &font->global_subrs_index );
+ cff_index_done( &font->font_dict_index );
+ cff_index_done( &font->name_index );
+ cff_index_done( &font->charstrings_index );
+
+ /* release font dictionaries, but only if working with */
+ /* a CID keyed CFF font or a CFF2 font */
+ if ( font->num_subfonts > 0 )
+ {
+ for ( idx = 0; idx < font->num_subfonts; idx++ )
+ cff_subfont_done( memory, font->subfonts[idx] );
+
+ /* the subfonts array has been allocated as a single block */
+ FT_FREE( font->subfonts[0] );
+ }
+
+ cff_encoding_done( &font->encoding );
+ cff_charset_done( &font->charset, font->stream );
+ cff_vstore_done( &font->vstore, memory );
+
+ cff_subfont_done( memory, &font->top_font );
+
+ CFF_Done_FD_Select( &font->fd_select, font->stream );
+
+ FT_FREE( font->font_info );
+
+ FT_FREE( font->font_name );
+ FT_FREE( font->global_subrs );
+ FT_FREE( font->strings );
+ FT_FREE( font->string_pool );
+
+ if ( font->cf2_instance.finalizer )
+ {
+ font->cf2_instance.finalizer( font->cf2_instance.data );
+ FT_FREE( font->cf2_instance.data );
+ }
+
+ FT_FREE( font->font_extra );
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffload.h b/modules/freetype2/src/cff/cffload.h
new file mode 100644
index 0000000000..5a41cdebc8
--- /dev/null
+++ b/modules/freetype2/src/cff/cffload.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+ *
+ * cffload.h
+ *
+ * OpenType & CFF data/program tables loader (specification).
+ *
+ * Copyright (C) 1996-2023 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 CFFLOAD_H_
+#define CFFLOAD_H_
+
+
+#include <freetype/internal/cfftypes.h>
+#include "cffparse.h"
+#include <freetype/internal/cffotypes.h> /* for CFF_Face */
+
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( FT_UShort )
+ cff_get_standard_encoding( FT_UInt charcode );
+
+
+ FT_LOCAL( FT_String* )
+ cff_index_get_string( CFF_Font font,
+ FT_UInt element );
+
+ FT_LOCAL( FT_String* )
+ cff_index_get_sid_string( CFF_Font font,
+ FT_UInt sid );
+
+
+ FT_LOCAL( FT_Error )
+ cff_index_access_element( CFF_Index idx,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len );
+
+ FT_LOCAL( void )
+ cff_index_forget_element( CFF_Index idx,
+ FT_Byte** pbytes );
+
+ FT_LOCAL( FT_String* )
+ cff_index_get_name( CFF_Font font,
+ FT_UInt element );
+
+
+ FT_LOCAL( FT_UInt )
+ cff_charset_cid_to_gindex( CFF_Charset charset,
+ FT_UInt cid );
+
+
+ FT_LOCAL( FT_Error )
+ cff_font_load( FT_Library library,
+ FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font font,
+ CFF_Face face,
+ FT_Bool pure_cff,
+ FT_Bool cff2 );
+
+ FT_LOCAL( void )
+ cff_font_done( CFF_Font font );
+
+
+ FT_LOCAL( FT_Error )
+ cff_load_private_dict( CFF_Font font,
+ CFF_SubFont subfont,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV );
+
+ FT_LOCAL( FT_Byte )
+ cff_fd_select_get( CFF_FDSelect fdselect,
+ FT_UInt glyph_index );
+
+ FT_LOCAL( FT_Bool )
+ cff_blend_check_vector( CFF_Blend blend,
+ FT_UInt vsindex,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV );
+
+ FT_LOCAL( FT_Error )
+ cff_blend_build_vector( CFF_Blend blend,
+ FT_UInt vsindex,
+ FT_UInt lenNDV,
+ FT_Fixed* NDV );
+
+ FT_LOCAL( void )
+ cff_blend_clear( CFF_SubFont subFont );
+
+ FT_LOCAL( FT_Error )
+ cff_blend_doBlend( CFF_SubFont subfont,
+ CFF_Parser parser,
+ FT_UInt numBlends );
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ FT_LOCAL( FT_Error )
+ cff_get_var_blend( CFF_Face face,
+ FT_UInt *num_coords,
+ FT_Fixed* *coords,
+ FT_Fixed* *normalizedcoords,
+ FT_MM_Var* *mm_var );
+
+ FT_LOCAL( void )
+ cff_done_blend( CFF_Face face );
+#endif
+
+
+FT_END_HEADER
+
+#endif /* CFFLOAD_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffobjs.c b/modules/freetype2/src/cff/cffobjs.c
new file mode 100644
index 0000000000..40cd9bf917
--- /dev/null
+++ b/modules/freetype2/src/cff/cffobjs.c
@@ -0,0 +1,1214 @@
+/****************************************************************************
+ *
+ * cffobjs.c
+ *
+ * OpenType objects manager (body).
+ *
+ * Copyright (C) 1996-2023 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftcalc.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/fterrors.h>
+#include <freetype/ttnameid.h>
+#include <freetype/tttags.h>
+#include <freetype/internal/sfnt.h>
+#include <freetype/ftdriver.h>
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include <freetype/ftmm.h>
+#include <freetype/internal/services/svmm.h>
+#include <freetype/internal/services/svmetric.h>
+#endif
+
+#include <freetype/internal/cffotypes.h>
+#include "cffobjs.h"
+#include "cffload.h"
+#include "cffcmap.h"
+
+#include "cfferrs.h"
+
+#include <freetype/internal/psaux.h>
+#include <freetype/internal/services/svcfftl.h>
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT cffobjs
+
+
+ /**************************************************************************
+ *
+ * SIZE FUNCTIONS
+ *
+ */
+
+
+ static PSH_Globals_Funcs
+ cff_size_get_globals_funcs( CFF_Size size )
+ {
+ CFF_Face face = (CFF_Face)size->root.face;
+ CFF_Font font = (CFF_Font)face->extra.data;
+ PSHinter_Service pshinter = font->pshinter;
+ FT_Module module;
+
+
+ module = FT_Get_Module( size->root.face->driver->root.library,
+ "pshinter" );
+ return ( module && pshinter && pshinter->get_globals_funcs )
+ ? pshinter->get_globals_funcs( module )
+ : 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_size_done( FT_Size cffsize ) /* CFF_Size */
+ {
+ FT_Memory memory = cffsize->face->memory;
+ CFF_Size size = (CFF_Size)cffsize;
+ CFF_Face face = (CFF_Face)size->root.face;
+ CFF_Font font = (CFF_Font)face->extra.data;
+ CFF_Internal internal = (CFF_Internal)cffsize->internal->module_data;
+
+
+ if ( internal )
+ {
+ PSH_Globals_Funcs funcs;
+
+
+ funcs = cff_size_get_globals_funcs( size );
+ if ( funcs )
+ {
+ FT_UInt i;
+
+
+ funcs->destroy( internal->topfont );
+
+ for ( i = font->num_subfonts; i > 0; i-- )
+ funcs->destroy( internal->subfonts[i - 1] );
+ }
+
+ FT_FREE( internal );
+ }
+ }
+
+
+ /* CFF and Type 1 private dictionaries have slightly different */
+ /* structures; we need to synthesize a Type 1 dictionary on the fly */
+
+ static void
+ cff_make_private_dict( CFF_SubFont subfont,
+ PS_Private priv )
+ {
+ CFF_Private cpriv = &subfont->private_dict;
+ FT_UInt n, count;
+
+
+ FT_ZERO( priv );
+
+ count = priv->num_blue_values = cpriv->num_blue_values;
+ for ( n = 0; n < count; n++ )
+ priv->blue_values[n] = (FT_Short)cpriv->blue_values[n];
+
+ count = priv->num_other_blues = cpriv->num_other_blues;
+ for ( n = 0; n < count; n++ )
+ priv->other_blues[n] = (FT_Short)cpriv->other_blues[n];
+
+ count = priv->num_family_blues = cpriv->num_family_blues;
+ for ( n = 0; n < count; n++ )
+ priv->family_blues[n] = (FT_Short)cpriv->family_blues[n];
+
+ count = priv->num_family_other_blues = cpriv->num_family_other_blues;
+ for ( n = 0; n < count; n++ )
+ priv->family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
+
+ priv->blue_scale = cpriv->blue_scale;
+ priv->blue_shift = (FT_Int)cpriv->blue_shift;
+ priv->blue_fuzz = (FT_Int)cpriv->blue_fuzz;
+
+ priv->standard_width[0] = (FT_UShort)cpriv->standard_width;
+ priv->standard_height[0] = (FT_UShort)cpriv->standard_height;
+
+ count = priv->num_snap_widths = cpriv->num_snap_widths;
+ for ( n = 0; n < count; n++ )
+ priv->snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
+
+ count = priv->num_snap_heights = cpriv->num_snap_heights;
+ for ( n = 0; n < count; n++ )
+ priv->snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
+
+ priv->force_bold = cpriv->force_bold;
+ priv->language_group = cpriv->language_group;
+ priv->lenIV = cpriv->lenIV;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_size_init( FT_Size cffsize ) /* CFF_Size */
+ {
+ CFF_Size size = (CFF_Size)cffsize;
+ FT_Error error = FT_Err_Ok;
+ PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size );
+
+ FT_Memory memory = cffsize->face->memory;
+ CFF_Internal internal = NULL;
+ CFF_Face face = (CFF_Face)cffsize->face;
+ CFF_Font font = (CFF_Font)face->extra.data;
+
+ PS_PrivateRec priv;
+
+ FT_UInt i;
+
+ if ( !funcs )
+ goto Exit;
+
+ if ( FT_NEW( internal ) )
+ goto Exit;
+
+ cff_make_private_dict( &font->top_font, &priv );
+ error = funcs->create( cffsize->face->memory, &priv,
+ &internal->topfont );
+ if ( error )
+ goto Exit;
+
+ for ( i = font->num_subfonts; i > 0; i-- )
+ {
+ CFF_SubFont sub = font->subfonts[i - 1];
+
+
+ cff_make_private_dict( sub, &priv );
+ error = funcs->create( cffsize->face->memory, &priv,
+ &internal->subfonts[i - 1] );
+ if ( error )
+ goto Exit;
+ }
+
+ cffsize->internal->module_data = internal;
+
+ size->strike_index = 0xFFFFFFFFUL;
+
+ Exit:
+ if ( error )
+ {
+ if ( internal )
+ {
+ for ( i = font->num_subfonts; i > 0; i-- )
+ FT_FREE( internal->subfonts[i - 1] );
+ FT_FREE( internal->topfont );
+ }
+
+ FT_FREE( internal );
+ }
+
+ return error;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_size_select( FT_Size size,
+ FT_ULong strike_index )
+ {
+ CFF_Size cffsize = (CFF_Size)size;
+ PSH_Globals_Funcs funcs;
+
+
+ cffsize->strike_index = strike_index;
+
+ FT_Select_Metrics( size->face, strike_index );
+
+ funcs = cff_size_get_globals_funcs( cffsize );
+
+ if ( funcs )
+ {
+ CFF_Face face = (CFF_Face)size->face;
+ CFF_Font font = (CFF_Font)face->extra.data;
+ CFF_Internal internal = (CFF_Internal)size->internal->module_data;
+
+ FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em;
+ FT_UInt i;
+
+
+ funcs->set_scale( internal->topfont,
+ size->metrics.x_scale, size->metrics.y_scale,
+ 0, 0 );
+
+ for ( i = font->num_subfonts; i > 0; i-- )
+ {
+ CFF_SubFont sub = font->subfonts[i - 1];
+ FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em;
+ FT_Pos x_scale, y_scale;
+
+
+ if ( top_upm != sub_upm )
+ {
+ x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
+ y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
+ }
+ else
+ {
+ x_scale = size->metrics.x_scale;
+ y_scale = size->metrics.y_scale;
+ }
+
+ funcs->set_scale( internal->subfonts[i - 1],
+ x_scale, y_scale, 0, 0 );
+ }
+ }
+
+ return FT_Err_Ok;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_size_request( FT_Size size,
+ FT_Size_Request req )
+ {
+ FT_Error error;
+
+ CFF_Size cffsize = (CFF_Size)size;
+ PSH_Globals_Funcs funcs;
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ if ( FT_HAS_FIXED_SIZES( size->face ) )
+ {
+ CFF_Face cffface = (CFF_Face)size->face;
+ SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
+ FT_ULong strike_index;
+
+
+ if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) )
+ cffsize->strike_index = 0xFFFFFFFFUL;
+ else
+ return cff_size_select( size, strike_index );
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ error = FT_Request_Metrics( size->face, req );
+ if ( error )
+ goto Exit;
+
+ funcs = cff_size_get_globals_funcs( cffsize );
+
+ if ( funcs )
+ {
+ CFF_Face cffface = (CFF_Face)size->face;
+ CFF_Font font = (CFF_Font)cffface->extra.data;
+ CFF_Internal internal = (CFF_Internal)size->internal->module_data;
+
+ FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em;
+ FT_UInt i;
+
+
+ funcs->set_scale( internal->topfont,
+ size->metrics.x_scale, size->metrics.y_scale,
+ 0, 0 );
+
+ for ( i = font->num_subfonts; i > 0; i-- )
+ {
+ CFF_SubFont sub = font->subfonts[i - 1];
+ FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em;
+ FT_Pos x_scale, y_scale;
+
+
+ if ( top_upm != sub_upm )
+ {
+ x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
+ y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
+ }
+ else
+ {
+ x_scale = size->metrics.x_scale;
+ y_scale = size->metrics.y_scale;
+ }
+
+ funcs->set_scale( internal->subfonts[i - 1],
+ x_scale, y_scale, 0, 0 );
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /**************************************************************************
+ *
+ * SLOT FUNCTIONS
+ *
+ */
+
+ FT_LOCAL_DEF( void )
+ cff_slot_done( FT_GlyphSlot slot )
+ {
+ if ( slot->internal )
+ slot->internal->glyph_hints = NULL;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_slot_init( FT_GlyphSlot slot )
+ {
+ CFF_Face face = (CFF_Face)slot->face;
+ CFF_Font font = (CFF_Font)face->extra.data;
+ PSHinter_Service pshinter = font->pshinter;
+
+
+ if ( pshinter )
+ {
+ FT_Module module;
+
+
+ module = FT_Get_Module( slot->face->driver->root.library,
+ "pshinter" );
+ if ( module )
+ {
+ T2_Hints_Funcs funcs;
+
+
+ funcs = pshinter->get_t2_funcs( module );
+ slot->internal->glyph_hints = (void*)funcs;
+ }
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /**************************************************************************
+ *
+ * FACE FUNCTIONS
+ *
+ */
+
+ static FT_String*
+ cff_strcpy( FT_Memory memory,
+ const FT_String* source )
+ {
+ FT_Error error;
+ FT_String* result;
+
+
+ FT_MEM_STRDUP( result, source );
+
+ return result;
+ }
+
+
+ /* Strip all subset prefixes of the form `ABCDEF+'. Usually, there */
+ /* is only one, but font names like `APCOOG+JFABTD+FuturaBQ-Bold' */
+ /* have been seen in the wild. */
+
+ static void
+ remove_subset_prefix( FT_String* name )
+ {
+ FT_Int32 idx = 0;
+ FT_Int32 length = (FT_Int32)ft_strlen( name ) + 1;
+ FT_Bool continue_search = 1;
+
+
+ while ( continue_search )
+ {
+ if ( length >= 7 && name[6] == '+' )
+ {
+ for ( idx = 0; idx < 6; idx++ )
+ {
+ /* ASCII uppercase letters */
+ if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) )
+ continue_search = 0;
+ }
+
+ if ( continue_search )
+ {
+ for ( idx = 7; idx < length; idx++ )
+ name[idx - 7] = name[idx];
+ length -= 7;
+ }
+ }
+ else
+ continue_search = 0;
+ }
+ }
+
+
+ /* Remove the style part from the family name (if present). */
+
+ static void
+ remove_style( FT_String* family_name,
+ const FT_String* style_name )
+ {
+ FT_Int32 family_name_length, style_name_length;
+
+
+ family_name_length = (FT_Int32)ft_strlen( family_name );
+ style_name_length = (FT_Int32)ft_strlen( style_name );
+
+ if ( family_name_length > style_name_length )
+ {
+ FT_Int idx;
+
+
+ for ( idx = 1; idx <= style_name_length; idx++ )
+ {
+ if ( family_name[family_name_length - idx] !=
+ style_name[style_name_length - idx] )
+ break;
+ }
+
+ if ( idx > style_name_length )
+ {
+ /* family_name ends with style_name; remove it */
+ idx = family_name_length - style_name_length - 1;
+
+ /* also remove special characters */
+ /* between real family name and style */
+ while ( idx > 0 &&
+ ( family_name[idx] == '-' ||
+ family_name[idx] == ' ' ||
+ family_name[idx] == '_' ||
+ family_name[idx] == '+' ) )
+ idx--;
+
+ if ( idx > 0 )
+ family_name[idx + 1] = '\0';
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_face_init( FT_Stream stream,
+ FT_Face cffface, /* CFF_Face */
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ CFF_Face face = (CFF_Face)cffface;
+ FT_Error error;
+ SFNT_Service sfnt;
+ FT_Service_PsCMaps psnames;
+ PSHinter_Service pshinter;
+ PSAux_Service psaux;
+ FT_Service_CFFLoad cffload;
+ FT_Bool pure_cff = 1;
+ FT_Bool cff2 = 0;
+ FT_Bool sfnt_format = 0;
+ FT_Library library = cffface->driver->root.library;
+
+
+ sfnt = (SFNT_Service)FT_Get_Module_Interface( library,
+ "sfnt" );
+ if ( !sfnt )
+ {
+ FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+
+ FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
+
+ pshinter = (PSHinter_Service)FT_Get_Module_Interface( library,
+ "pshinter" );
+
+ psaux = (PSAux_Service)FT_Get_Module_Interface( library,
+ "psaux" );
+ if ( !psaux )
+ {
+ FT_ERROR(( "cff_face_init: cannot access `psaux' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+ face->psaux = psaux;
+
+ FT_FACE_FIND_GLOBAL_SERVICE( face, cffload, CFF_LOAD );
+
+ FT_TRACE2(( "CFF driver\n" ));
+
+ /* create input stream from resource */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ /* check whether we have a valid OpenType file */
+ FT_TRACE2(( " " ));
+ error = sfnt->init_face( stream, face, face_index, num_params, params );
+ if ( !error )
+ {
+ if ( face->format_tag != TTAG_OTTO ) /* `OTTO'; OpenType/CFF font */
+ {
+ FT_TRACE2(( " not an OpenType/CFF font\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
+ /* if we are performing a simple font format check, exit immediately */
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+
+ sfnt_format = 1;
+
+ /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
+ /* font; in the latter case it doesn't have a `head' table */
+ error = face->goto_table( face, TTAG_head, stream, 0 );
+ if ( !error )
+ {
+ pure_cff = 0;
+
+ /* load font directory */
+ error = sfnt->load_face( stream, face, face_index,
+ num_params, params );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* load the `cmap' table explicitly */
+ error = sfnt->load_cmap( face, stream );
+ if ( error )
+ goto Exit;
+ }
+
+ /* now load the CFF part of the file; */
+ /* give priority to CFF2 */
+ error = face->goto_table( face, TTAG_CFF2, stream, 0 );
+ if ( !error )
+ {
+ cff2 = 1;
+ face->is_cff2 = cff2;
+ }
+
+ if ( FT_ERR_EQ( error, Table_Missing ) )
+ error = face->goto_table( face, TTAG_CFF, stream, 0 );
+
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* rewind to start of file; we are going to load a pure-CFF font */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+ error = FT_Err_Ok;
+ }
+
+ /* now load and parse the CFF table in the file */
+ {
+ CFF_Font cff = NULL;
+ CFF_FontRecDict dict;
+ FT_Memory memory = cffface->memory;
+ FT_Int32 flags;
+ FT_UInt i;
+
+
+ if ( FT_NEW( cff ) )
+ goto Exit;
+
+ face->extra.data = cff;
+ error = cff_font_load( library,
+ stream,
+ face_index,
+ cff,
+ face,
+ pure_cff,
+ cff2 );
+ if ( error )
+ goto Exit;
+
+ /* if we are performing a simple font format check, exit immediately */
+ /* (this is here for pure CFF) */
+ if ( face_index < 0 )
+ {
+ cffface->num_faces = (FT_Long)cff->num_faces;
+ return FT_Err_Ok;
+ }
+
+ cff->pshinter = pshinter;
+ cff->psnames = psnames;
+ cff->cffload = cffload;
+
+ cffface->face_index = face_index & 0xFFFF;
+
+ /* Complement the root flags with some interesting information. */
+ /* Note that this is only necessary for pure CFF and CEF fonts; */
+ /* SFNT based fonts use the `name' table instead. */
+
+ cffface->num_glyphs = (FT_Long)cff->num_glyphs;
+
+ dict = &cff->top_font.font_dict;
+
+ /* we need the `psnames' module for CFF and CEF formats */
+ /* which aren't CID-keyed */
+ if ( dict->cid_registry == 0xFFFFU && !psnames )
+ {
+ FT_ERROR(( "cff_face_init:"
+ " cannot open CFF & CEF fonts\n" ));
+ FT_ERROR(( " "
+ " without the `psnames' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_UInt idx;
+ FT_String* s;
+
+
+ FT_TRACE4(( "SIDs\n" ));
+
+ /* dump string index, including default strings for convenience */
+ for ( idx = 0; idx <= 390; idx++ )
+ {
+ s = cff_index_get_sid_string( cff, idx );
+ if ( s )
+ FT_TRACE4(( " %5d %s\n", idx, s ));
+ }
+
+ /* In Multiple Master CFFs, two SIDs hold the Normalize Design */
+ /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */
+ /* which may contain null bytes in the middle of the data, too. */
+ /* We thus access `cff->strings' directly. */
+ for ( idx = 1; idx < cff->num_strings; idx++ )
+ {
+ FT_Byte* s1 = cff->strings[idx - 1];
+ FT_Byte* s2 = cff->strings[idx];
+ FT_PtrDist s1len = s2 - s1 - 1; /* without the final null byte */
+ FT_PtrDist l;
+
+
+ FT_TRACE4(( " %5d ", idx + 390 ));
+ for ( l = 0; l < s1len; l++ )
+ FT_TRACE4(( "%c", s1[l] ));
+ FT_TRACE4(( "\n" ));
+ }
+
+ /* print last element */
+ if ( cff->num_strings )
+ {
+ FT_Byte* s1 = cff->strings[cff->num_strings - 1];
+ FT_Byte* s2 = cff->string_pool + cff->string_pool_size;
+ FT_PtrDist s1len = s2 - s1 - 1;
+ FT_PtrDist l;
+
+
+ FT_TRACE4(( " %5d ", cff->num_strings + 390 ));
+ for ( l = 0; l < s1len; l++ )
+ FT_TRACE4(( "%c", s1[l] ));
+ FT_TRACE4(( "\n" ));
+ }
+ }
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ {
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+
+ FT_UInt instance_index = (FT_UInt)face_index >> 16;
+
+
+ if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
+ mm &&
+ instance_index > 0 )
+ {
+ error = mm->set_instance( cffface, instance_index );
+ if ( error )
+ goto Exit;
+
+ if ( var )
+ var->metrics_adjust( cffface );
+ }
+ }
+#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
+
+ if ( !dict->has_font_matrix )
+ dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM;
+
+ /* Normalize the font matrix so that `matrix->yy' is 1; if */
+ /* it is zero, we use `matrix->yx' instead. The scaling is */
+ /* done with `units_per_em' then (at this point, it already */
+ /* contains the scaling factor, but without normalization */
+ /* of the matrix). */
+ /* */
+ /* Note that the offsets must be expressed in integer font */
+ /* units. */
+
+ {
+ FT_Matrix* matrix = &dict->font_matrix;
+ FT_Vector* offset = &dict->font_offset;
+ FT_ULong* upm = &dict->units_per_em;
+ FT_Fixed temp;
+
+
+ temp = matrix->yy ? FT_ABS( matrix->yy )
+ : FT_ABS( matrix->yx );
+
+ if ( temp != 0x10000L )
+ {
+ *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp );
+
+ matrix->xx = FT_DivFix( matrix->xx, temp );
+ matrix->yx = FT_DivFix( matrix->yx, temp );
+ matrix->xy = FT_DivFix( matrix->xy, temp );
+ matrix->yy = FT_DivFix( matrix->yy, temp );
+ offset->x = FT_DivFix( offset->x, temp );
+ offset->y = FT_DivFix( offset->y, temp );
+ }
+
+ offset->x >>= 16;
+ offset->y >>= 16;
+ }
+
+ for ( i = cff->num_subfonts; i > 0; i-- )
+ {
+ CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict;
+ CFF_FontRecDict top = &cff->top_font.font_dict;
+
+ FT_Matrix* matrix;
+ FT_Vector* offset;
+ FT_ULong* upm;
+ FT_Fixed temp;
+
+
+ if ( sub->has_font_matrix )
+ {
+ FT_Long scaling;
+
+
+ /* if we have a top-level matrix, */
+ /* concatenate the subfont matrix */
+
+ if ( top->has_font_matrix )
+ {
+ if ( top->units_per_em > 1 && sub->units_per_em > 1 )
+ scaling = (FT_Long)FT_MIN( top->units_per_em,
+ sub->units_per_em );
+ else
+ scaling = 1;
+
+ FT_Matrix_Multiply_Scaled( &top->font_matrix,
+ &sub->font_matrix,
+ scaling );
+ FT_Vector_Transform_Scaled( &sub->font_offset,
+ &top->font_matrix,
+ scaling );
+
+ sub->units_per_em = (FT_ULong)
+ FT_MulDiv( (FT_Long)sub->units_per_em,
+ (FT_Long)top->units_per_em,
+ scaling );
+ }
+ }
+ else
+ {
+ sub->font_matrix = top->font_matrix;
+ sub->font_offset = top->font_offset;
+
+ sub->units_per_em = top->units_per_em;
+ }
+
+ matrix = &sub->font_matrix;
+ offset = &sub->font_offset;
+ upm = &sub->units_per_em;
+
+ temp = matrix->yy ? FT_ABS( matrix->yy )
+ : FT_ABS( matrix->yx );
+
+
+ if ( temp != 0x10000L )
+ {
+ *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp );
+
+ matrix->xx = FT_DivFix( matrix->xx, temp );
+ matrix->yx = FT_DivFix( matrix->yx, temp );
+ matrix->xy = FT_DivFix( matrix->xy, temp );
+ matrix->yy = FT_DivFix( matrix->yy, temp );
+ offset->x = FT_DivFix( offset->x, temp );
+ offset->y = FT_DivFix( offset->y, temp );
+ }
+
+ offset->x >>= 16;
+ offset->y >>= 16;
+ }
+
+ if ( pure_cff )
+ {
+ char* style_name = NULL;
+
+
+ /* set up num_faces */
+ cffface->num_faces = (FT_Long)cff->num_faces;
+
+ /* compute number of glyphs */
+ if ( dict->cid_registry != 0xFFFFU )
+ cffface->num_glyphs = (FT_Long)( cff->charset.max_cid + 1 );
+ else
+ cffface->num_glyphs = (FT_Long)cff->charstrings_index.count;
+
+ /* set global bbox, as well as EM size */
+ cffface->bbox.xMin = dict->font_bbox.xMin >> 16;
+ cffface->bbox.yMin = dict->font_bbox.yMin >> 16;
+ /* no `U' suffix here to 0xFFFF! */
+ cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16;
+ cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16;
+
+ cffface->units_per_EM = (FT_UShort)( dict->units_per_em );
+
+ cffface->ascender = (FT_Short)( cffface->bbox.yMax );
+ cffface->descender = (FT_Short)( cffface->bbox.yMin );
+
+ cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 );
+ if ( cffface->height < cffface->ascender - cffface->descender )
+ cffface->height = (FT_Short)( cffface->ascender -
+ cffface->descender );
+
+ cffface->underline_position =
+ (FT_Short)( dict->underline_position >> 16 );
+ cffface->underline_thickness =
+ (FT_Short)( dict->underline_thickness >> 16 );
+
+ /* retrieve font family & style name */
+ if ( dict->family_name )
+ {
+ char* family_name;
+
+
+ family_name = cff_index_get_sid_string( cff, dict->family_name );
+ if ( family_name )
+ cffface->family_name = cff_strcpy( memory, family_name );
+ }
+
+ if ( !cffface->family_name )
+ {
+ cffface->family_name = cff_index_get_name(
+ cff,
+ (FT_UInt)( face_index & 0xFFFF ) );
+ if ( cffface->family_name )
+ remove_subset_prefix( cffface->family_name );
+ }
+
+ if ( cffface->family_name )
+ {
+ char* full = cff_index_get_sid_string( cff,
+ dict->full_name );
+ char* fullp = full;
+ char* family = cffface->family_name;
+
+
+ /* We try to extract the style name from the full name. */
+ /* We need to ignore spaces and dashes during the search. */
+ if ( full && family )
+ {
+ while ( *fullp )
+ {
+ /* skip common characters at the start of both strings */
+ if ( *fullp == *family )
+ {
+ family++;
+ fullp++;
+ continue;
+ }
+
+ /* ignore spaces and dashes in full name during comparison */
+ if ( *fullp == ' ' || *fullp == '-' )
+ {
+ fullp++;
+ continue;
+ }
+
+ /* ignore spaces and dashes in family name during comparison */
+ if ( *family == ' ' || *family == '-' )
+ {
+ family++;
+ continue;
+ }
+
+ if ( !*family && *fullp )
+ {
+ /* The full name begins with the same characters as the */
+ /* family name, with spaces and dashes removed. In this */
+ /* case, the remaining string in `fullp' will be used as */
+ /* the style name. */
+ style_name = cff_strcpy( memory, fullp );
+
+ /* remove the style part from the family name (if present) */
+ if ( style_name )
+ remove_style( cffface->family_name, style_name );
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ char *cid_font_name =
+ cff_index_get_sid_string( cff,
+ dict->cid_font_name );
+
+
+ /* do we have a `/FontName' for a CID-keyed font? */
+ if ( cid_font_name )
+ cffface->family_name = cff_strcpy( memory, cid_font_name );
+ }
+
+ if ( style_name )
+ cffface->style_name = style_name;
+ else
+ /* assume "Regular" style if we don't know better */
+ cffface->style_name = cff_strcpy( memory, "Regular" );
+
+ /********************************************************************
+ *
+ * Compute face flags.
+ */
+ flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */
+ FT_FACE_FLAG_HORIZONTAL | /* horizontal data */
+ FT_FACE_FLAG_HINTER; /* has native hinter */
+
+ if ( sfnt_format )
+ flags |= FT_FACE_FLAG_SFNT;
+
+ /* fixed width font? */
+ if ( dict->is_fixed_pitch )
+ flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
+#if 0
+ /* kerning available? */
+ if ( face->kern_pairs )
+ flags |= FT_FACE_FLAG_KERNING;
+#endif
+
+ cffface->face_flags |= flags;
+
+ /********************************************************************
+ *
+ * Compute style flags.
+ */
+ flags = 0;
+
+ if ( dict->italic_angle )
+ flags |= FT_STYLE_FLAG_ITALIC;
+
+ {
+ char *weight = cff_index_get_sid_string( cff,
+ dict->weight );
+
+
+ if ( weight )
+ if ( !ft_strcmp( weight, "Bold" ) ||
+ !ft_strcmp( weight, "Black" ) )
+ flags |= FT_STYLE_FLAG_BOLD;
+ }
+
+ /* double check */
+ if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name )
+ if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) ||
+ !ft_strncmp( cffface->style_name, "Black", 5 ) )
+ flags |= FT_STYLE_FLAG_BOLD;
+
+ cffface->style_flags = flags;
+ }
+
+ /* CID-keyed CFF or CFF2 fonts don't have glyph names -- the SFNT */
+ /* loader has unset this flag because of the 3.0 `post' table. */
+ if ( dict->cid_registry == 0xFFFFU && !cff2 )
+ cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+ if ( dict->cid_registry != 0xFFFFU && pure_cff )
+ cffface->face_flags |= FT_FACE_FLAG_CID_KEYED;
+
+ /********************************************************************
+ *
+ * Compute char maps.
+ */
+
+ /* Try to synthesize a Unicode charmap if there is none available */
+ /* already. If an OpenType font contains a Unicode "cmap", we */
+ /* will use it, whatever be in the CFF part of the file. */
+ {
+ FT_CharMapRec cmaprec;
+ FT_CharMap cmap;
+ FT_Int nn;
+ CFF_Encoding encoding = &cff->encoding;
+
+
+ for ( nn = 0; nn < cffface->num_charmaps; nn++ )
+ {
+ cmap = cffface->charmaps[nn];
+
+ /* Windows Unicode? */
+ if ( cmap->platform_id == TT_PLATFORM_MICROSOFT &&
+ cmap->encoding_id == TT_MS_ID_UNICODE_CS )
+ goto Skip_Unicode;
+
+ /* Apple Unicode platform id? */
+ if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE )
+ goto Skip_Unicode; /* Apple Unicode */
+ }
+
+ /* since CID-keyed fonts don't contain glyph names, we can't */
+ /* construct a cmap */
+ if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU )
+ goto Exit;
+
+ /* we didn't find a Unicode charmap -- synthesize one */
+ cmaprec.face = cffface;
+ cmaprec.platform_id = TT_PLATFORM_MICROSOFT;
+ cmaprec.encoding_id = TT_MS_ID_UNICODE_CS;
+ cmaprec.encoding = FT_ENCODING_UNICODE;
+
+ nn = cffface->num_charmaps;
+
+ error = FT_CMap_New( &cff_cmap_unicode_class_rec, NULL,
+ &cmaprec, NULL );
+ if ( error &&
+ FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) &&
+ FT_ERR_NEQ( error, Unimplemented_Feature ) )
+ goto Exit;
+ error = FT_Err_Ok;
+
+ /* if no Unicode charmap was previously selected, select this one */
+ if ( !cffface->charmap && nn != cffface->num_charmaps )
+ cffface->charmap = cffface->charmaps[nn];
+
+ Skip_Unicode:
+ if ( encoding->count > 0 )
+ {
+ FT_CMap_Class clazz;
+
+
+ cmaprec.face = cffface;
+ cmaprec.platform_id = TT_PLATFORM_ADOBE; /* Adobe platform id */
+
+ if ( encoding->offset == 0 )
+ {
+ cmaprec.encoding_id = TT_ADOBE_ID_STANDARD;
+ cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+ else if ( encoding->offset == 1 )
+ {
+ cmaprec.encoding_id = TT_ADOBE_ID_EXPERT;
+ cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+ else
+ {
+ cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM;
+ cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+
+ error = FT_CMap_New( clazz, NULL, &cmaprec, NULL );
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_face_done( FT_Face cffface ) /* CFF_Face */
+ {
+ CFF_Face face = (CFF_Face)cffface;
+ FT_Memory memory;
+ SFNT_Service sfnt;
+
+
+ if ( !face )
+ return;
+
+ memory = cffface->memory;
+ sfnt = (SFNT_Service)face->sfnt;
+
+ if ( sfnt )
+ sfnt->done_face( face );
+
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+
+ if ( cff )
+ {
+ cff_font_done( cff );
+ FT_FREE( face->extra.data );
+ }
+ }
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ cff_done_blend( face );
+ face->blend = NULL;
+#endif
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_driver_init( FT_Module module ) /* CFF_Driver */
+ {
+ PS_Driver driver = (PS_Driver)module;
+
+ FT_UInt32 seed;
+
+
+ /* set default property values, cf. `ftcffdrv.h' */
+ driver->hinting_engine = FT_HINTING_ADOBE;
+
+ driver->no_stem_darkening = TRUE;
+
+ driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
+ driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
+ driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
+ driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
+ driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
+ driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
+ driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
+ driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
+
+ /* compute random seed from some memory addresses */
+ seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^
+ (FT_Offset)(char*)&module ^
+ (FT_Offset)(char*)module->memory );
+ seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
+
+ driver->random_seed = (FT_Int32)seed;
+ if ( driver->random_seed < 0 )
+ driver->random_seed = -driver->random_seed;
+ else if ( driver->random_seed == 0 )
+ driver->random_seed = 123456789;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_driver_done( FT_Module module ) /* CFF_Driver */
+ {
+ FT_UNUSED( module );
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffobjs.h b/modules/freetype2/src/cff/cffobjs.h
new file mode 100644
index 0000000000..8f05f6132b
--- /dev/null
+++ b/modules/freetype2/src/cff/cffobjs.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+ *
+ * cffobjs.h
+ *
+ * OpenType objects manager (specification).
+ *
+ * Copyright (C) 1996-2023 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 CFFOBJS_H_
+#define CFFOBJS_H_
+
+
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ cff_size_init( FT_Size size ); /* CFF_Size */
+
+ FT_LOCAL( void )
+ cff_size_done( FT_Size size ); /* CFF_Size */
+
+ FT_LOCAL( FT_Error )
+ cff_size_request( FT_Size size,
+ FT_Size_Request req );
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL( FT_Error )
+ cff_size_select( FT_Size size,
+ FT_ULong strike_index );
+
+#endif
+
+ FT_LOCAL( void )
+ cff_slot_done( FT_GlyphSlot slot );
+
+ FT_LOCAL( FT_Error )
+ cff_slot_init( FT_GlyphSlot slot );
+
+
+ /**************************************************************************
+ *
+ * Face functions
+ */
+ FT_LOCAL( FT_Error )
+ cff_face_init( FT_Stream stream,
+ FT_Face face, /* CFF_Face */
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ cff_face_done( FT_Face face ); /* CFF_Face */
+
+
+ /**************************************************************************
+ *
+ * Driver functions
+ */
+ FT_LOCAL( FT_Error )
+ cff_driver_init( FT_Module module ); /* PS_Driver */
+
+ FT_LOCAL( void )
+ cff_driver_done( FT_Module module ); /* PS_Driver */
+
+
+FT_END_HEADER
+
+#endif /* CFFOBJS_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffparse.c b/modules/freetype2/src/cff/cffparse.c
new file mode 100644
index 0000000000..e16206fd55
--- /dev/null
+++ b/modules/freetype2/src/cff/cffparse.c
@@ -0,0 +1,1621 @@
+/****************************************************************************
+ *
+ * cffparse.c
+ *
+ * CFF token stream parser (body)
+ *
+ * Copyright (C) 1996-2023 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include "cffparse.h"
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftcalc.h>
+#include <freetype/internal/psaux.h>
+#include <freetype/ftlist.h>
+
+#include "cfferrs.h"
+#include "cffload.h"
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT cffparse
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_parser_init( CFF_Parser parser,
+ FT_UInt code,
+ void* object,
+ FT_Library library,
+ FT_UInt stackSize,
+ FT_UShort num_designs,
+ FT_UShort num_axes )
+ {
+ FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */
+ FT_Error error; /* for FT_NEW_ARRAY */
+
+
+ FT_ZERO( parser );
+
+#if 0
+ parser->top = parser->stack;
+#endif
+ parser->object_code = code;
+ parser->object = object;
+ parser->library = library;
+ parser->num_designs = num_designs;
+ parser->num_axes = num_axes;
+
+ /* allocate the stack buffer */
+ if ( FT_QNEW_ARRAY( parser->stack, stackSize ) )
+ {
+ FT_FREE( parser->stack );
+ goto Exit;
+ }
+
+ parser->stackSize = stackSize;
+ parser->top = parser->stack; /* empty stack */
+
+ Exit:
+ return error;
+ }
+
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ static void
+ finalize_t2_strings( FT_Memory memory,
+ void* data,
+ void* user )
+ {
+ CFF_T2_String t2 = (CFF_T2_String)data;
+
+
+ FT_UNUSED( user );
+
+ memory->free( memory, t2->start );
+ memory->free( memory, data );
+ }
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
+
+ FT_LOCAL_DEF( void )
+ cff_parser_done( CFF_Parser parser )
+ {
+ FT_Memory memory = parser->library->memory; /* for FT_FREE */
+
+
+ FT_FREE( parser->stack );
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ FT_List_Finalize( &parser->t2_strings,
+ finalize_t2_strings,
+ memory,
+ NULL );
+#endif
+ }
+
+
+ /* Assuming `first >= last'. */
+
+ static FT_Error
+ cff_parser_within_limits( CFF_Parser parser,
+ FT_Byte* first,
+ FT_Byte* last )
+ {
+#ifndef CFF_CONFIG_OPTION_OLD_ENGINE
+
+ /* Fast path for regular FreeType builds with the "new" engine; */
+ /* `first >= parser->start' can be assumed. */
+
+ FT_UNUSED( first );
+
+ return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument );
+
+#else /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
+ FT_ListNode node;
+
+
+ if ( first >= parser->start &&
+ last < parser->limit )
+ return FT_Err_Ok;
+
+ node = parser->t2_strings.head;
+
+ while ( node )
+ {
+ CFF_T2_String t2 = (CFF_T2_String)node->data;
+
+
+ if ( first >= t2->start &&
+ last < t2->limit )
+ return FT_Err_Ok;
+
+ node = node->next;
+ }
+
+ return FT_THROW( Invalid_Argument );
+
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+ }
+
+
+ /* read an integer */
+ static FT_Long
+ cff_parse_integer( CFF_Parser parser,
+ FT_Byte* start )
+ {
+ FT_Byte* p = start;
+ FT_Int v = *p++;
+ FT_Long val = 0;
+
+
+ if ( v == 28 )
+ {
+ if ( cff_parser_within_limits( parser, p, p + 1 ) )
+ goto Bad;
+
+ val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] );
+ }
+ else if ( v == 29 )
+ {
+ if ( cff_parser_within_limits( parser, p, p + 3 ) )
+ goto Bad;
+
+ val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) |
+ ( (FT_ULong)p[1] << 16 ) |
+ ( (FT_ULong)p[2] << 8 ) |
+ (FT_ULong)p[3] );
+ }
+ else if ( v < 247 )
+ {
+ val = v - 139;
+ }
+ else if ( v < 251 )
+ {
+ if ( cff_parser_within_limits( parser, p, p ) )
+ goto Bad;
+
+ val = ( v - 247 ) * 256 + p[0] + 108;
+ }
+ else
+ {
+ if ( cff_parser_within_limits( parser, p, p ) )
+ goto Bad;
+
+ val = -( v - 251 ) * 256 - p[0] - 108;
+ }
+
+ Exit:
+ return val;
+
+ Bad:
+ val = 0;
+ FT_TRACE4(( "!!!END OF DATA:!!!" ));
+ goto Exit;
+ }
+
+
+ static const FT_Long power_tens[] =
+ {
+ 1L,
+ 10L,
+ 100L,
+ 1000L,
+ 10000L,
+ 100000L,
+ 1000000L,
+ 10000000L,
+ 100000000L,
+ 1000000000L
+ };
+
+ /* maximum values allowed for multiplying */
+ /* with the corresponding `power_tens' element */
+ static const FT_Long power_ten_limits[] =
+ {
+ FT_LONG_MAX / 1L,
+ FT_LONG_MAX / 10L,
+ FT_LONG_MAX / 100L,
+ FT_LONG_MAX / 1000L,
+ FT_LONG_MAX / 10000L,
+ FT_LONG_MAX / 100000L,
+ FT_LONG_MAX / 1000000L,
+ FT_LONG_MAX / 10000000L,
+ FT_LONG_MAX / 100000000L,
+ FT_LONG_MAX / 1000000000L,
+ };
+
+
+ /* read a real */
+ static FT_Fixed
+ cff_parse_real( CFF_Parser parser,
+ FT_Byte* start,
+ FT_Long power_ten,
+ FT_Long* scaling )
+ {
+ FT_Byte* p = start;
+ FT_Int nib;
+ FT_UInt phase;
+
+ FT_Long result, number, exponent;
+ FT_Int sign = 0, exponent_sign = 0, have_overflow = 0;
+ FT_Long exponent_add, integer_length, fraction_length;
+
+
+ if ( scaling )
+ *scaling = 0;
+
+ result = 0;
+
+ number = 0;
+ exponent = 0;
+
+ exponent_add = 0;
+ integer_length = 0;
+ fraction_length = 0;
+
+ /* First of all, read the integer part. */
+ phase = 4;
+
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need to */
+ /* read a new byte. This also skips past the initial 0x1E. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( cff_parser_within_limits( parser, p, p ) )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = (FT_Int)( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+
+ if ( nib == 0xE )
+ sign = 1;
+ else if ( nib > 9 )
+ break;
+ else
+ {
+ /* Increase exponent if we can't add the digit. */
+ if ( number >= 0xCCCCCCCL )
+ exponent_add++;
+ /* Skip leading zeros. */
+ else if ( nib || number )
+ {
+ integer_length++;
+ number = number * 10 + nib;
+ }
+ }
+ }
+
+ /* Read fraction part, if any. */
+ if ( nib == 0xA )
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need */
+ /* to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( cff_parser_within_limits( parser, p, p ) )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ /* Skip leading zeros if possible. */
+ if ( !nib && !number )
+ exponent_add--;
+ /* Only add digit if we don't overflow. */
+ else if ( number < 0xCCCCCCCL && fraction_length < 9 )
+ {
+ fraction_length++;
+ number = number * 10 + nib;
+ }
+ }
+
+ /* Read exponent, if any. */
+ if ( nib == 12 )
+ {
+ exponent_sign = 1;
+ nib = 11;
+ }
+
+ if ( nib == 11 )
+ {
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, */
+ /* we need to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( cff_parser_within_limits( parser, p, p ) )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ /* Arbitrarily limit exponent. */
+ if ( exponent > 1000 )
+ have_overflow = 1;
+ else
+ exponent = exponent * 10 + nib;
+ }
+
+ if ( exponent_sign )
+ exponent = -exponent;
+ }
+
+ if ( !number )
+ goto Exit;
+
+ if ( have_overflow )
+ {
+ if ( exponent_sign )
+ goto Underflow;
+ else
+ goto Overflow;
+ }
+
+ /* We don't check `power_ten' and `exponent_add'. */
+ exponent += power_ten + exponent_add;
+
+ if ( scaling )
+ {
+ /* Only use `fraction_length'. */
+ fraction_length += integer_length;
+ exponent += integer_length;
+
+ if ( fraction_length <= 5 )
+ {
+ if ( number > 0x7FFFL )
+ {
+ result = FT_DivFix( number, 10 );
+ *scaling = exponent - fraction_length + 1;
+ }
+ else
+ {
+ if ( exponent > 0 )
+ {
+ FT_Long new_fraction_length, shift;
+
+
+ /* Make `scaling' as small as possible. */
+ new_fraction_length = FT_MIN( exponent, 5 );
+ shift = new_fraction_length - fraction_length;
+
+ if ( shift > 0 )
+ {
+ exponent -= new_fraction_length;
+ number *= power_tens[shift];
+ if ( number > 0x7FFFL )
+ {
+ number /= 10;
+ exponent += 1;
+ }
+ }
+ else
+ exponent -= fraction_length;
+ }
+ else
+ exponent -= fraction_length;
+
+ result = (FT_Long)( (FT_ULong)number << 16 );
+ *scaling = exponent;
+ }
+ }
+ else
+ {
+ if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL )
+ {
+ result = FT_DivFix( number, power_tens[fraction_length - 4] );
+ *scaling = exponent - 4;
+ }
+ else
+ {
+ result = FT_DivFix( number, power_tens[fraction_length - 5] );
+ *scaling = exponent - 5;
+ }
+ }
+ }
+ else
+ {
+ integer_length += exponent;
+ fraction_length -= exponent;
+
+ if ( integer_length > 5 )
+ goto Overflow;
+ if ( integer_length < -5 )
+ goto Underflow;
+
+ /* Remove non-significant digits. */
+ if ( integer_length < 0 )
+ {
+ number /= power_tens[-integer_length];
+ fraction_length += integer_length;
+ }
+
+ /* this can only happen if exponent was non-zero */
+ if ( fraction_length == 10 )
+ {
+ number /= 10;
+ fraction_length -= 1;
+ }
+
+ /* Convert into 16.16 format. */
+ if ( fraction_length > 0 )
+ {
+ if ( ( number / power_tens[fraction_length] ) > 0x7FFFL )
+ goto Exit;
+
+ result = FT_DivFix( number, power_tens[fraction_length] );
+ }
+ else
+ {
+ number *= power_tens[-fraction_length];
+
+ if ( number > 0x7FFFL )
+ goto Overflow;
+
+ result = (FT_Long)( (FT_ULong)number << 16 );
+ }
+ }
+
+ Exit:
+ if ( sign )
+ result = -result;
+
+ return result;
+
+ Overflow:
+ result = 0x7FFFFFFFL;
+ FT_TRACE4(( "!!!OVERFLOW:!!!" ));
+ goto Exit;
+
+ Underflow:
+ result = 0;
+ FT_TRACE4(( "!!!UNDERFLOW:!!!" ));
+ goto Exit;
+
+ Bad:
+ result = 0;
+ FT_TRACE4(( "!!!END OF DATA:!!!" ));
+ goto Exit;
+ }
+
+
+ /* read a number, either integer or real */
+ FT_LOCAL_DEF( FT_Long )
+ cff_parse_num( CFF_Parser parser,
+ FT_Byte** d )
+ {
+ if ( **d == 30 )
+ {
+ /* binary-coded decimal is truncated to integer */
+ return cff_parse_real( parser, *d, 0, NULL ) >> 16;
+ }
+
+ else if ( **d == 255 )
+ {
+ /* 16.16 fixed-point is used internally for CFF2 blend results. */
+ /* Since these are trusted values, a limit check is not needed. */
+
+ /* After the 255, 4 bytes give the number. */
+ /* The blend value is converted to integer, with rounding; */
+ /* due to the right-shift we don't need the lowest byte. */
+#if 0
+ return (FT_Short)(
+ ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) |
+ ( (FT_UInt32)*( d[0] + 2 ) << 16 ) |
+ ( (FT_UInt32)*( d[0] + 3 ) << 8 ) |
+ (FT_UInt32)*( d[0] + 4 ) ) + 0x8000U ) >> 16 );
+#else
+ return (FT_Short)(
+ ( ( ( (FT_UInt32)*( d[0] + 1 ) << 16 ) |
+ ( (FT_UInt32)*( d[0] + 2 ) << 8 ) |
+ (FT_UInt32)*( d[0] + 3 ) ) + 0x80U ) >> 8 );
+#endif
+ }
+
+ else
+ return cff_parse_integer( parser, *d );
+ }
+
+
+ /* read a floating point number, either integer or real */
+ static FT_Fixed
+ do_fixed( CFF_Parser parser,
+ FT_Byte** d,
+ FT_Long scaling )
+ {
+ if ( **d == 30 )
+ return cff_parse_real( parser, *d, scaling, NULL );
+ else
+ {
+ FT_Long val = cff_parse_integer( parser, *d );
+
+
+ if ( scaling )
+ {
+ if ( FT_ABS( val ) > power_ten_limits[scaling] )
+ {
+ val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL;
+ goto Overflow;
+ }
+
+ val *= power_tens[scaling];
+ }
+
+ if ( val > 0x7FFF )
+ {
+ val = 0x7FFFFFFFL;
+ goto Overflow;
+ }
+ else if ( val < -0x7FFF )
+ {
+ val = -0x7FFFFFFFL;
+ goto Overflow;
+ }
+
+ return (FT_Long)( (FT_ULong)val << 16 );
+
+ Overflow:
+ FT_TRACE4(( "!!!OVERFLOW:!!!" ));
+ return val;
+ }
+ }
+
+
+ /* read a floating point number, either integer or real */
+ static FT_Fixed
+ cff_parse_fixed( CFF_Parser parser,
+ FT_Byte** d )
+ {
+ return do_fixed( parser, d, 0 );
+ }
+
+
+ /* read a floating point number, either integer or real, */
+ /* but return `10^scaling' times the number read in */
+ static FT_Fixed
+ cff_parse_fixed_scaled( CFF_Parser parser,
+ FT_Byte** d,
+ FT_Long scaling )
+ {
+ return do_fixed( parser, d, scaling );
+ }
+
+
+ /* read a floating point number, either integer or real, */
+ /* and return it as precise as possible -- `scaling' returns */
+ /* the scaling factor (as a power of 10) */
+ static FT_Fixed
+ cff_parse_fixed_dynamic( CFF_Parser parser,
+ FT_Byte** d,
+ FT_Long* scaling )
+ {
+ FT_ASSERT( scaling );
+
+ if ( **d == 30 )
+ return cff_parse_real( parser, *d, 0, scaling );
+ else
+ {
+ FT_Long number;
+ FT_Int integer_length;
+
+
+ number = cff_parse_integer( parser, d[0] );
+
+ if ( number > 0x7FFFL )
+ {
+ for ( integer_length = 5; integer_length < 10; integer_length++ )
+ if ( number < power_tens[integer_length] )
+ break;
+
+ if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL )
+ {
+ *scaling = integer_length - 4;
+ return FT_DivFix( number, power_tens[integer_length - 4] );
+ }
+ else
+ {
+ *scaling = integer_length - 5;
+ return FT_DivFix( number, power_tens[integer_length - 5] );
+ }
+ }
+ else
+ {
+ *scaling = 0;
+ return (FT_Long)( (FT_ULong)number << 16 );
+ }
+ }
+ }
+
+
+ static FT_Error
+ cff_parse_font_matrix( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Matrix* matrix = &dict->font_matrix;
+ FT_Vector* offset = &dict->font_offset;
+ FT_ULong* upm = &dict->units_per_em;
+ FT_Byte** data = parser->stack;
+
+
+ if ( parser->top >= parser->stack + 6 )
+ {
+ FT_Fixed values[6];
+ FT_Long scalings[6];
+
+ FT_Long min_scaling, max_scaling;
+ int i;
+
+
+ dict->has_font_matrix = TRUE;
+
+ /* We expect a well-formed font matrix, this is, the matrix elements */
+ /* `xx' and `yy' are of approximately the same magnitude. To avoid */
+ /* loss of precision, we use the magnitude of the largest matrix */
+ /* element to scale all other elements. The scaling factor is then */
+ /* contained in the `units_per_em' value. */
+
+ max_scaling = FT_LONG_MIN;
+ min_scaling = FT_LONG_MAX;
+
+ for ( i = 0; i < 6; i++ )
+ {
+ values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] );
+ if ( values[i] )
+ {
+ if ( scalings[i] > max_scaling )
+ max_scaling = scalings[i];
+ if ( scalings[i] < min_scaling )
+ min_scaling = scalings[i];
+ }
+ }
+
+ if ( max_scaling < -9 ||
+ max_scaling > 0 ||
+ ( max_scaling - min_scaling ) < 0 ||
+ ( max_scaling - min_scaling ) > 9 )
+ {
+ FT_TRACE1(( "cff_parse_font_matrix:"
+ " strange scaling values (minimum %ld, maximum %ld),\n",
+ min_scaling, max_scaling ));
+ FT_TRACE1(( " "
+ " using default matrix\n" ));
+ goto Unlikely;
+ }
+
+ for ( i = 0; i < 6; i++ )
+ {
+ FT_Fixed value = values[i];
+ FT_Long divisor, half_divisor;
+
+
+ if ( !value )
+ continue;
+
+ divisor = power_tens[max_scaling - scalings[i]];
+ half_divisor = divisor >> 1;
+
+ if ( value < 0 )
+ {
+ if ( FT_LONG_MIN + half_divisor < value )
+ values[i] = ( value - half_divisor ) / divisor;
+ else
+ values[i] = FT_LONG_MIN / divisor;
+ }
+ else
+ {
+ if ( FT_LONG_MAX - half_divisor > value )
+ values[i] = ( value + half_divisor ) / divisor;
+ else
+ values[i] = FT_LONG_MAX / divisor;
+ }
+ }
+
+ matrix->xx = values[0];
+ matrix->yx = values[1];
+ matrix->xy = values[2];
+ matrix->yy = values[3];
+ offset->x = values[4];
+ offset->y = values[5];
+
+ *upm = (FT_ULong)power_tens[-max_scaling];
+
+ FT_TRACE4(( " [%f %f %f %f %f %f]\n",
+ (double)matrix->xx / (double)*upm / 65536,
+ (double)matrix->xy / (double)*upm / 65536,
+ (double)matrix->yx / (double)*upm / 65536,
+ (double)matrix->yy / (double)*upm / 65536,
+ (double)offset->x / (double)*upm / 65536,
+ (double)offset->y / (double)*upm / 65536 ));
+
+ if ( !FT_Matrix_Check( matrix ) )
+ {
+ FT_TRACE1(( "cff_parse_font_matrix:"
+ " degenerate values, using default matrix\n" ));
+ goto Unlikely;
+ }
+
+ return FT_Err_Ok;
+ }
+ else
+ return FT_THROW( Stack_Underflow );
+
+ Unlikely:
+ /* Return default matrix in case of unlikely values. */
+
+ matrix->xx = 0x10000L;
+ matrix->yx = 0;
+ matrix->xy = 0;
+ matrix->yy = 0x10000L;
+ offset->x = 0;
+ offset->y = 0;
+ *upm = 1;
+
+ return FT_Err_Ok;
+ }
+
+
+ static FT_Error
+ cff_parse_font_bbox( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_BBox* bbox = &dict->font_bbox;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = FT_ERR( Stack_Underflow );
+
+ if ( parser->top >= parser->stack + 4 )
+ {
+ bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
+ bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
+ bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
+ bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) );
+ error = FT_Err_Ok;
+
+ FT_TRACE4(( " [%ld %ld %ld %ld]\n",
+ bbox->xMin / 65536,
+ bbox->yMin / 65536,
+ bbox->xMax / 65536,
+ bbox->yMax / 65536 ));
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_private_dict( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = FT_ERR( Stack_Underflow );
+
+ if ( parser->top >= parser->stack + 2 )
+ {
+ FT_Long tmp;
+
+
+ tmp = cff_parse_num( parser, data++ );
+ if ( tmp < 0 )
+ {
+ FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Fail;
+ }
+ dict->private_size = (FT_ULong)tmp;
+
+ tmp = cff_parse_num( parser, data );
+ if ( tmp < 0 )
+ {
+ FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Fail;
+ }
+ dict->private_offset = (FT_ULong)tmp;
+
+ FT_TRACE4(( " %lu %lu\n",
+ dict->private_size, dict->private_offset ));
+
+ error = FT_Err_Ok;
+ }
+
+ Fail:
+ return error;
+ }
+
+
+ /* The `MultipleMaster' operator comes before any */
+ /* top DICT operators that contain T2 charstrings. */
+
+ static FT_Error
+ cff_parse_multiple_master( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Error error;
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ /* beautify tracing message */
+ if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] < 4 )
+ FT_TRACE1(( "Multiple Master CFFs not supported yet,"
+ " handling first master design only\n" ));
+ else
+ FT_TRACE1(( " (not supported yet,"
+ " handling first master design only)\n" ));
+#endif
+
+ error = FT_ERR( Stack_Underflow );
+
+ /* currently, we handle only the first argument */
+ if ( parser->top >= parser->stack + 5 )
+ {
+ FT_Long num_designs = cff_parse_num( parser, parser->stack );
+
+
+ if ( num_designs > 16 || num_designs < 2 )
+ {
+ FT_ERROR(( "cff_parse_multiple_master:"
+ " Invalid number of designs\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ }
+ else
+ {
+ dict->num_designs = (FT_UShort)num_designs;
+ dict->num_axes = (FT_UShort)( parser->top - parser->stack - 4 );
+
+ parser->num_designs = dict->num_designs;
+ parser->num_axes = dict->num_axes;
+
+ error = FT_Err_Ok;
+ }
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_cid_ros( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = FT_ERR( Stack_Underflow );
+
+ if ( parser->top >= parser->stack + 3 )
+ {
+ dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ );
+ dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ );
+ if ( **data == 30 )
+ FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" ));
+ dict->cid_supplement = cff_parse_num( parser, data );
+ if ( dict->cid_supplement < 0 )
+ FT_TRACE1(( "cff_parse_cid_ros: negative supplement %ld is found\n",
+ dict->cid_supplement ));
+ error = FT_Err_Ok;
+
+ FT_TRACE4(( " %d %d %ld\n",
+ dict->cid_registry,
+ dict->cid_ordering,
+ dict->cid_supplement ));
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_vsindex( CFF_Parser parser )
+ {
+ /* vsindex operator can only be used in a Private DICT */
+ CFF_Private priv = (CFF_Private)parser->object;
+ FT_Byte** data = parser->stack;
+ CFF_Blend blend;
+ FT_Error error;
+
+
+ if ( !priv || !priv->subfont )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ blend = &priv->subfont->blend;
+
+ if ( blend->usedBV )
+ {
+ FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" ));
+ error = FT_THROW( Syntax_Error );
+ goto Exit;
+ }
+
+ priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ );
+
+ FT_TRACE4(( " %d\n", priv->vsindex ));
+
+ error = FT_Err_Ok;
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_blend( CFF_Parser parser )
+ {
+ /* blend operator can only be used in a Private DICT */
+ CFF_Private priv = (CFF_Private)parser->object;
+ CFF_SubFont subFont;
+ CFF_Blend blend;
+ FT_UInt numBlends;
+ FT_Error error;
+
+
+ if ( !priv || !priv->subfont )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ subFont = priv->subfont;
+ blend = &subFont->blend;
+
+ if ( cff_blend_check_vector( blend,
+ priv->vsindex,
+ subFont->lenNDV,
+ subFont->NDV ) )
+ {
+ error = cff_blend_build_vector( blend,
+ priv->vsindex,
+ subFont->lenNDV,
+ subFont->NDV );
+ if ( error )
+ goto Exit;
+ }
+
+ numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 );
+ if ( numBlends > parser->stackSize )
+ {
+ FT_ERROR(( "cff_parse_blend: Invalid number of blends\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ FT_TRACE4(( " %d value%s blended\n",
+ numBlends,
+ numBlends == 1 ? "" : "s" ));
+
+ error = cff_blend_doBlend( subFont, parser, numBlends );
+
+ blend->usedBV = TRUE;
+
+ Exit:
+ return error;
+ }
+
+
+ /* maxstack operator increases parser and operand stacks for CFF2 */
+ static FT_Error
+ cff_parse_maxstack( CFF_Parser parser )
+ {
+ /* maxstack operator can only be used in a Top DICT */
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !dict )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ );
+ if ( dict->maxstack > CFF2_MAX_STACK )
+ dict->maxstack = CFF2_MAX_STACK;
+ if ( dict->maxstack < CFF2_DEFAULT_STACK )
+ dict->maxstack = CFF2_DEFAULT_STACK;
+
+ FT_TRACE4(( " %d\n", dict->maxstack ));
+
+ Exit:
+ return error;
+ }
+
+
+#define CFF_FIELD_NUM( code, name, id ) \
+ CFF_FIELD( code, name, id, cff_kind_num )
+#define CFF_FIELD_FIXED( code, name, id ) \
+ CFF_FIELD( code, name, id, cff_kind_fixed )
+#define CFF_FIELD_FIXED_1000( code, name, id ) \
+ CFF_FIELD( code, name, id, cff_kind_fixed_thousand )
+#define CFF_FIELD_STRING( code, name, id ) \
+ CFF_FIELD( code, name, id, cff_kind_string )
+#define CFF_FIELD_BOOL( code, name, id ) \
+ CFF_FIELD( code, name, id, cff_kind_bool )
+
+
+#undef CFF_FIELD
+#undef CFF_FIELD_DELTA
+
+
+#ifndef FT_DEBUG_LEVEL_TRACE
+
+
+#define CFF_FIELD_CALLBACK( code, name, id ) \
+ { \
+ cff_kind_callback, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_ ## name, \
+ 0, 0 \
+ },
+
+#define CFF_FIELD_BLEND( code, id ) \
+ { \
+ cff_kind_blend, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_blend, \
+ 0, 0 \
+ },
+
+#define CFF_FIELD( code, name, id, kind ) \
+ { \
+ kind, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE( name ), \
+ 0, 0, 0 \
+ },
+
+#define CFF_FIELD_DELTA( code, name, max, id ) \
+ { \
+ cff_kind_delta, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE_DELTA( name ), \
+ 0, \
+ max, \
+ FT_FIELD_OFFSET( num_ ## name ) \
+ },
+
+ static const CFF_Field_Handler cff_field_handlers[] =
+ {
+
+#include "cfftoken.h"
+
+ { 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+#else /* FT_DEBUG_LEVEL_TRACE */
+
+
+
+#define CFF_FIELD_CALLBACK( code, name, id ) \
+ { \
+ cff_kind_callback, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_ ## name, \
+ 0, 0, \
+ id \
+ },
+
+#define CFF_FIELD_BLEND( code, id ) \
+ { \
+ cff_kind_blend, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_blend, \
+ 0, 0, \
+ id \
+ },
+
+#define CFF_FIELD( code, name, id, kind ) \
+ { \
+ kind, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE( name ), \
+ 0, 0, 0, \
+ id \
+ },
+
+#define CFF_FIELD_DELTA( code, name, max, id ) \
+ { \
+ cff_kind_delta, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE_DELTA( name ), \
+ 0, \
+ max, \
+ FT_FIELD_OFFSET( num_ ## name ), \
+ id \
+ },
+
+ static const CFF_Field_Handler cff_field_handlers[] =
+ {
+
+#include "cfftoken.h"
+
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_parser_run( CFF_Parser parser,
+ FT_Byte* start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = start;
+ FT_Error error = FT_Err_Ok;
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ PSAux_Service psaux;
+
+ FT_Library library = parser->library;
+ FT_Memory memory = library->memory;
+#endif
+
+ parser->top = parser->stack;
+ parser->start = start;
+ parser->limit = limit;
+ parser->cursor = start;
+
+ while ( p < limit )
+ {
+ FT_UInt v = *p;
+
+
+ /* Opcode 31 is legacy MM T2 operator, not a number. */
+ /* Opcode 255 is reserved and should not appear in fonts; */
+ /* it is used internally for CFF2 blends. */
+ if ( v >= 27 && v != 31 && v != 255 )
+ {
+ /* it's a number; we will push its position on the stack */
+ if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
+ goto Stack_Overflow;
+
+ *parser->top++ = p;
+
+ /* now, skip it */
+ if ( v == 30 )
+ {
+ /* skip real number */
+ p++;
+ for (;;)
+ {
+ /* An unterminated floating point number at the */
+ /* end of a dictionary is invalid but harmless. */
+ if ( p >= limit )
+ goto Exit;
+ v = p[0] >> 4;
+ if ( v == 15 )
+ break;
+ v = p[0] & 0xF;
+ if ( v == 15 )
+ break;
+ p++;
+ }
+ }
+ else if ( v == 28 )
+ p += 2;
+ else if ( v == 29 )
+ p += 4;
+ else if ( v > 246 )
+ p += 1;
+ }
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ else if ( v == 31 )
+ {
+ /* a Type 2 charstring */
+
+ CFF_Decoder decoder;
+ CFF_FontRec cff_rec;
+ FT_Byte* charstring_base;
+ FT_ULong charstring_len;
+
+ FT_Fixed* stack;
+ FT_ListNode node;
+ CFF_T2_String t2;
+ FT_Fixed t2_size;
+ FT_Byte* q;
+
+
+ charstring_base = ++p;
+
+ /* search `endchar' operator */
+ for (;;)
+ {
+ if ( p >= limit )
+ goto Exit;
+ if ( *p == 14 )
+ break;
+ p++;
+ }
+
+ charstring_len = (FT_ULong)( p - charstring_base ) + 1;
+
+ /* construct CFF_Decoder object */
+ FT_ZERO( &decoder );
+ FT_ZERO( &cff_rec );
+
+ cff_rec.top_font.font_dict.num_designs = parser->num_designs;
+ cff_rec.top_font.font_dict.num_axes = parser->num_axes;
+ decoder.cff = &cff_rec;
+
+ psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" );
+ if ( !psaux )
+ {
+ FT_ERROR(( "cff_parser_run: cannot access `psaux' module\n" ));
+ error = FT_THROW( Missing_Module );
+ goto Exit;
+ }
+
+ error = psaux->cff_decoder_funcs->parse_charstrings_old(
+ &decoder, charstring_base, charstring_len, 1 );
+ if ( error )
+ goto Exit;
+
+ /* Now copy the stack data in the temporary decoder object, */
+ /* converting it back to charstring number representations */
+ /* (this is ugly, I know). */
+
+ node = (FT_ListNode)memory->alloc( memory,
+ sizeof ( FT_ListNodeRec ) );
+ if ( !node )
+ goto Out_Of_Memory_Error;
+
+ FT_List_Add( &parser->t2_strings, node );
+
+ t2 = (CFF_T2_String)memory->alloc( memory,
+ sizeof ( CFF_T2_StringRec ) );
+ if ( !t2 )
+ goto Out_Of_Memory_Error;
+
+ node->data = t2;
+
+ /* `5' is the conservative upper bound of required bytes per stack */
+ /* element. */
+
+ t2_size = 5 * ( decoder.top - decoder.stack );
+
+ q = (FT_Byte*)memory->alloc( memory, t2_size );
+ if ( !q )
+ goto Out_Of_Memory_Error;
+
+ t2->start = q;
+ t2->limit = q + t2_size;
+
+ stack = decoder.stack;
+
+ while ( stack < decoder.top )
+ {
+ FT_ULong num;
+ FT_Bool neg;
+
+
+ if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
+ goto Stack_Overflow;
+
+ *parser->top++ = q;
+
+ if ( *stack < 0 )
+ {
+ num = (FT_ULong)NEG_LONG( *stack );
+ neg = 1;
+ }
+ else
+ {
+ num = (FT_ULong)*stack;
+ neg = 0;
+ }
+
+ if ( num & 0xFFFFU )
+ {
+ if ( neg )
+ num = (FT_ULong)-num;
+
+ *q++ = 255;
+ *q++ = ( num & 0xFF000000U ) >> 24;
+ *q++ = ( num & 0x00FF0000U ) >> 16;
+ *q++ = ( num & 0x0000FF00U ) >> 8;
+ *q++ = num & 0x000000FFU;
+ }
+ else
+ {
+ num >>= 16;
+
+ if ( neg )
+ {
+ if ( num <= 107 )
+ *q++ = (FT_Byte)( 139 - num );
+ else if ( num <= 1131 )
+ {
+ *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
+ *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+ }
+ else
+ {
+ num = (FT_ULong)-num;
+
+ *q++ = 28;
+ *q++ = (FT_Byte)( num >> 8 );
+ *q++ = (FT_Byte)( num & 0xFF );
+ }
+ }
+ else
+ {
+ if ( num <= 107 )
+ *q++ = (FT_Byte)( num + 139 );
+ else if ( num <= 1131 )
+ {
+ *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
+ *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+ }
+ else
+ {
+ *q++ = 28;
+ *q++ = (FT_Byte)( num >> 8 );
+ *q++ = (FT_Byte)( num & 0xFF );
+ }
+ }
+ }
+
+ stack++;
+ }
+ }
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+ else
+ {
+ /* This is not a number, hence it's an operator. Compute its code */
+ /* and look for it in our current list. */
+
+ FT_UInt code;
+ FT_UInt num_args;
+ const CFF_Field_Handler* field;
+
+
+ if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
+ goto Stack_Overflow;
+
+ num_args = (FT_UInt)( parser->top - parser->stack );
+ *parser->top = p;
+ code = v;
+
+ if ( v == 12 )
+ {
+ /* two byte operator */
+ p++;
+ if ( p >= limit )
+ goto Syntax_Error;
+
+ code = 0x100 | p[0];
+ }
+ code = code | parser->object_code;
+
+ for ( field = cff_field_handlers; field->kind; field++ )
+ {
+ if ( field->code == (FT_Int)code )
+ {
+ /* we found our field's handler; read it */
+ FT_Long val;
+ FT_Byte* q = (FT_Byte*)parser->object + field->offset;
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE4(( " %s", field->id ));
+#endif
+
+ /* check that we have enough arguments -- except for */
+ /* delta encoded arrays, which can be empty */
+ if ( field->kind != cff_kind_delta && num_args < 1 )
+ goto Stack_Underflow;
+
+ switch ( field->kind )
+ {
+ case cff_kind_bool:
+ case cff_kind_string:
+ case cff_kind_num:
+ val = cff_parse_num( parser, parser->stack );
+ goto Store_Number;
+
+ case cff_kind_fixed:
+ val = cff_parse_fixed( parser, parser->stack );
+ goto Store_Number;
+
+ case cff_kind_fixed_thousand:
+ val = cff_parse_fixed_scaled( parser, parser->stack, 3 );
+
+ Store_Number:
+ switch ( field->size )
+ {
+ case (8 / FT_CHAR_BIT):
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case (16 / FT_CHAR_BIT):
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case (32 / FT_CHAR_BIT):
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ switch ( field->kind )
+ {
+ case cff_kind_bool:
+ FT_TRACE4(( " %s\n", val ? "true" : "false" ));
+ break;
+
+ case cff_kind_string:
+ FT_TRACE4(( " %ld (SID)\n", val ));
+ break;
+
+ case cff_kind_num:
+ FT_TRACE4(( " %ld\n", val ));
+ break;
+
+ case cff_kind_fixed:
+ FT_TRACE4(( " %f\n", (double)val / 65536 ));
+ break;
+
+ case cff_kind_fixed_thousand:
+ FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 ));
+ break;
+
+ default:
+ ; /* never reached */
+ }
+#endif
+
+ break;
+
+ case cff_kind_delta:
+ {
+ FT_Byte* qcount = (FT_Byte*)parser->object +
+ field->count_offset;
+
+ FT_Byte** data = parser->stack;
+
+
+ if ( num_args > field->array_max )
+ num_args = field->array_max;
+
+ FT_TRACE4(( " [" ));
+
+ /* store count */
+ *qcount = (FT_Byte)num_args;
+
+ val = 0;
+ while ( num_args > 0 )
+ {
+ val = ADD_LONG( val, cff_parse_num( parser, data++ ) );
+ switch ( field->size )
+ {
+ case (8 / FT_CHAR_BIT):
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case (16 / FT_CHAR_BIT):
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case (32 / FT_CHAR_BIT):
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+
+ FT_TRACE4(( " %ld", val ));
+
+ q += field->size;
+ num_args--;
+ }
+
+ FT_TRACE4(( "]\n" ));
+ }
+ break;
+
+ default: /* callback or blend */
+ error = field->reader( parser );
+ if ( error )
+ goto Exit;
+ }
+ goto Found;
+ }
+ }
+
+ /* this is an unknown operator, or it is unsupported; */
+ /* we will ignore it for now. */
+
+ Found:
+ /* clear stack */
+ /* TODO: could clear blend stack here, */
+ /* but we don't have access to subFont */
+ if ( field->kind != cff_kind_blend )
+ parser->top = parser->stack;
+ }
+ p++;
+ } /* while ( p < limit ) */
+
+ Exit:
+ return error;
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ Out_Of_Memory_Error:
+ error = FT_THROW( Out_Of_Memory );
+ goto Exit;
+#endif
+
+ Stack_Overflow:
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+
+ Stack_Underflow:
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+
+ Syntax_Error:
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cffparse.h b/modules/freetype2/src/cff/cffparse.h
new file mode 100644
index 0000000000..58d59fa4ac
--- /dev/null
+++ b/modules/freetype2/src/cff/cffparse.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+ *
+ * cffparse.h
+ *
+ * CFF token stream parser (specification)
+ *
+ * Copyright (C) 1996-2023 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 CFFPARSE_H_
+#define CFFPARSE_H_
+
+
+#include <freetype/internal/cfftypes.h>
+#include <freetype/internal/ftobjs.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /* CFF uses constant parser stack size; */
+ /* CFF2 can increase from default 193 */
+#define CFF_MAX_STACK_DEPTH 96
+
+ /*
+ * There are plans to remove the `maxstack' operator in a forthcoming
+ * revision of the CFF2 specification, increasing the (then static) stack
+ * size to 513. By making the default stack size equal to the maximum
+ * stack size, the operator is essentially disabled, which has the
+ * desired effect in FreeType.
+ */
+#define CFF2_MAX_STACK 513
+#define CFF2_DEFAULT_STACK 513
+
+#define CFF_CODE_TOPDICT 0x1000
+#define CFF_CODE_PRIVATE 0x2000
+#define CFF2_CODE_TOPDICT 0x3000
+#define CFF2_CODE_FONTDICT 0x4000
+#define CFF2_CODE_PRIVATE 0x5000
+
+
+ typedef struct CFF_ParserRec_
+ {
+ FT_Library library;
+ FT_Byte* start;
+ FT_Byte* limit;
+ FT_Byte* cursor;
+
+ FT_Byte** stack;
+ FT_Byte** top;
+ FT_UInt stackSize; /* allocated size */
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ FT_ListRec t2_strings;
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
+ FT_UInt object_code;
+ void* object;
+
+ FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
+ FT_UShort num_axes; /* a copy of `CFF_FontRecDict->num_axes' */
+
+ } CFF_ParserRec, *CFF_Parser;
+
+
+ FT_LOCAL( FT_Long )
+ cff_parse_num( CFF_Parser parser,
+ FT_Byte** d );
+
+ FT_LOCAL( FT_Error )
+ cff_parser_init( CFF_Parser parser,
+ FT_UInt code,
+ void* object,
+ FT_Library library,
+ FT_UInt stackSize,
+ FT_UShort num_designs,
+ FT_UShort num_axes );
+
+ FT_LOCAL( void )
+ cff_parser_done( CFF_Parser parser );
+
+ FT_LOCAL( FT_Error )
+ cff_parser_run( CFF_Parser parser,
+ FT_Byte* start,
+ FT_Byte* limit );
+
+
+ enum
+ {
+ cff_kind_none = 0,
+ cff_kind_num,
+ cff_kind_fixed,
+ cff_kind_fixed_thousand,
+ cff_kind_string,
+ cff_kind_bool,
+ cff_kind_delta,
+ cff_kind_callback,
+ cff_kind_blend,
+
+ cff_kind_max /* do not remove */
+ };
+
+
+ /* now generate handlers for the most simple fields */
+ typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser );
+
+ typedef struct CFF_Field_Handler_
+ {
+ int kind;
+ int code;
+ FT_UInt offset;
+ FT_Byte size;
+ CFF_Field_Reader reader;
+ FT_UInt array_max;
+ FT_UInt count_offset;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ const char* id;
+#endif
+
+ } CFF_Field_Handler;
+
+
+FT_END_HEADER
+
+
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+ typedef struct CFF_T2_String_
+ {
+ FT_Byte* start;
+ FT_Byte* limit;
+
+ } CFF_T2_StringRec, *CFF_T2_String;
+#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
+
+#endif /* CFFPARSE_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/cfftoken.h b/modules/freetype2/src/cff/cfftoken.h
new file mode 100644
index 0000000000..b61cb0e66e
--- /dev/null
+++ b/modules/freetype2/src/cff/cfftoken.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+ *
+ * cfftoken.h
+ *
+ * CFF token definitions (specification only).
+ *
+ * Copyright (C) 1996-2023 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.
+ *
+ */
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRecDictRec
+
+#undef CFFCODE
+#define CFFCODE CFF_CODE_TOPDICT
+
+ CFF_FIELD_STRING ( 0, version, "Version" )
+ CFF_FIELD_STRING ( 1, notice, "Notice" )
+ CFF_FIELD_STRING ( 0x100, copyright, "Copyright" )
+ CFF_FIELD_STRING ( 2, full_name, "FullName" )
+ CFF_FIELD_STRING ( 3, family_name, "FamilyName" )
+ CFF_FIELD_STRING ( 4, weight, "Weight" )
+ CFF_FIELD_BOOL ( 0x101, is_fixed_pitch, "isFixedPitch" )
+ CFF_FIELD_FIXED ( 0x102, italic_angle, "ItalicAngle" )
+ CFF_FIELD_FIXED ( 0x103, underline_position, "UnderlinePosition" )
+ CFF_FIELD_FIXED ( 0x104, underline_thickness, "UnderlineThickness" )
+ CFF_FIELD_NUM ( 0x105, paint_type, "PaintType" )
+ CFF_FIELD_NUM ( 0x106, charstring_type, "CharstringType" )
+ CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
+ CFF_FIELD_NUM ( 13, unique_id, "UniqueID" )
+ CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" )
+ CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" )
+#if 0
+ CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" )
+#endif
+ CFF_FIELD_NUM ( 15, charset_offset, "charset" )
+ CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" )
+ CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
+ CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
+ CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" )
+ CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" )
+
+#if 0
+ CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" )
+ CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" )
+#endif
+
+ /* the next two operators were removed from the Type2 specification */
+ /* in version 16-March-2000 */
+ CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" )
+#if 0
+ CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" )
+#endif
+
+ CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" )
+ CFF_FIELD_NUM ( 0x11F, cid_font_version, "CIDFontVersion" )
+ CFF_FIELD_NUM ( 0x120, cid_font_revision, "CIDFontRevision" )
+ CFF_FIELD_NUM ( 0x121, cid_font_type, "CIDFontType" )
+ CFF_FIELD_NUM ( 0x122, cid_count, "CIDCount" )
+ CFF_FIELD_NUM ( 0x123, cid_uid_base, "UIDBase" )
+ CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
+ CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
+ CFF_FIELD_STRING ( 0x126, cid_font_name, "FontName" )
+
+#if 0
+ CFF_FIELD_NUM ( 0x127, chameleon, "Chameleon" )
+#endif
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_PrivateRec
+#undef CFFCODE
+#define CFFCODE CFF_CODE_PRIVATE
+
+ CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
+ CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
+ CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
+ CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
+ CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
+ CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
+ CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
+ CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
+ CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
+ CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
+ CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
+ CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" )
+ CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" )
+ CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" )
+ CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
+ CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
+ CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" )
+ CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
+ CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
+ CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRecDictRec
+#undef CFFCODE
+#define CFFCODE CFF2_CODE_TOPDICT
+
+ CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
+ CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
+ CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
+ CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
+ CFF_FIELD_NUM ( 24, vstore_offset, "vstore" )
+ CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRecDictRec
+#undef CFFCODE
+#define CFFCODE CFF2_CODE_FONTDICT
+
+ CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
+ CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_PrivateRec
+#undef CFFCODE
+#define CFFCODE CFF2_CODE_PRIVATE
+
+ CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
+ CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
+ CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
+ CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
+ CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
+ CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
+ CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
+ CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
+ CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
+ CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
+ CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
+ CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
+ CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
+ CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" )
+ CFF_FIELD_BLEND ( 23, "blend" )
+ CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
+
+
+/* END */
diff --git a/modules/freetype2/src/cff/module.mk b/modules/freetype2/src/cff/module.mk
new file mode 100644
index 0000000000..b881d049f3
--- /dev/null
+++ b/modules/freetype2/src/cff/module.mk
@@ -0,0 +1,23 @@
+#
+# FreeType 2 CFF module definition
+#
+
+
+# Copyright (C) 1996-2023 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.
+
+
+FTMODULE_H_COMMANDS += CFF_DRIVER
+
+define CFF_DRIVER
+$(OPEN_DRIVER) FT_Driver_ClassRec, cff_driver_class $(CLOSE_DRIVER)
+$(ECHO_DRIVER)cff $(ECHO_DRIVER_DESC)OpenType fonts with extension *.otf$(ECHO_DRIVER_DONE)
+endef
+
+# EOF
diff --git a/modules/freetype2/src/cff/rules.mk b/modules/freetype2/src/cff/rules.mk
new file mode 100644
index 0000000000..629424adf7
--- /dev/null
+++ b/modules/freetype2/src/cff/rules.mk
@@ -0,0 +1,75 @@
+#
+# FreeType 2 OpenType/CFF driver configuration rules
+#
+
+
+# Copyright (C) 1996-2023 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.
+
+
+# OpenType driver directory
+#
+CFF_DIR := $(SRC_DIR)/cff
+
+
+CFF_COMPILE := $(CC) $(ANSIFLAGS) \
+ $I$(subst /,$(COMPILER_SEP),$(CFF_DIR)) \
+ $(INCLUDE_FLAGS) \
+ $(FT_CFLAGS)
+
+
+# CFF driver sources (i.e., C files)
+#
+CFF_DRV_SRC := $(CFF_DIR)/cffcmap.c \
+ $(CFF_DIR)/cffdrivr.c \
+ $(CFF_DIR)/cffgload.c \
+ $(CFF_DIR)/cffload.c \
+ $(CFF_DIR)/cffobjs.c \
+ $(CFF_DIR)/cffparse.c
+
+
+# CFF driver headers
+#
+CFF_DRV_H := $(CFF_DRV_SRC:%.c=%.h) \
+ $(CFF_DIR)/cfferrs.h \
+ $(CFF_DIR)/cfftoken.h
+
+
+# CFF driver object(s)
+#
+# CFF_DRV_OBJ_M is used during `multi' builds
+# CFF_DRV_OBJ_S is used during `single' builds
+#
+CFF_DRV_OBJ_M := $(CFF_DRV_SRC:$(CFF_DIR)/%.c=$(OBJ_DIR)/%.$O)
+CFF_DRV_OBJ_S := $(OBJ_DIR)/cff.$O
+
+# CFF driver source file for single build
+#
+CFF_DRV_SRC_S := $(CFF_DIR)/cff.c
+
+
+# CFF driver - single object
+#
+$(CFF_DRV_OBJ_S): $(CFF_DRV_SRC_S) $(CFF_DRV_SRC) $(FREETYPE_H) $(CFF_DRV_H)
+ $(CFF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(CFF_DRV_SRC_S))
+
+
+# CFF driver - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(CFF_DIR)/%.c $(FREETYPE_H) $(CFF_DRV_H)
+ $(CFF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(CFF_DRV_OBJ_S)
+DRV_OBJS_M += $(CFF_DRV_OBJ_M)
+
+
+# EOF