diff options
Diffstat (limited to 'modules/freetype2/src/pfr')
-rw-r--r-- | modules/freetype2/src/pfr/module.mk | 23 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfr.c | 29 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrcmap.c | 188 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrcmap.h | 45 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrdrivr.c | 212 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrdrivr.h | 36 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrerror.h | 41 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrgload.c | 849 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrgload.h | 49 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrload.c | 1062 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrload.h | 123 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrobjs.c | 603 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrobjs.h | 96 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrsbit.c | 813 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrsbit.h | 37 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/pfrtypes.h | 331 | ||||
-rw-r--r-- | modules/freetype2/src/pfr/rules.mk | 76 |
17 files changed, 4613 insertions, 0 deletions
diff --git a/modules/freetype2/src/pfr/module.mk b/modules/freetype2/src/pfr/module.mk new file mode 100644 index 0000000000..388a38ed09 --- /dev/null +++ b/modules/freetype2/src/pfr/module.mk @@ -0,0 +1,23 @@ +# +# FreeType 2 PFR module definition +# + + +# 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. + + +FTMODULE_H_COMMANDS += PFR_DRIVER + +define PFR_DRIVER +$(OPEN_DRIVER) FT_Driver_ClassRec, pfr_driver_class $(CLOSE_DRIVER) +$(ECHO_DRIVER)pfr $(ECHO_DRIVER_DESC)PFR/TrueDoc font files with extension *.pfr$(ECHO_DRIVER_DONE) +endef + +# EOF diff --git a/modules/freetype2/src/pfr/pfr.c b/modules/freetype2/src/pfr/pfr.c new file mode 100644 index 0000000000..d3738152dc --- /dev/null +++ b/modules/freetype2/src/pfr/pfr.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * pfr.c + * + * FreeType PFR driver component. + * + * 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. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pfrcmap.c" +#include "pfrdrivr.c" +#include "pfrgload.c" +#include "pfrload.c" +#include "pfrobjs.c" +#include "pfrsbit.c" + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrcmap.c b/modules/freetype2/src/pfr/pfrcmap.c new file mode 100644 index 0000000000..08fe41d54e --- /dev/null +++ b/modules/freetype2/src/pfr/pfrcmap.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * pfrcmap.c + * + * FreeType PFR cmap handling (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 "pfrcmap.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */ + FT_Pointer pointer ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_Error error = FT_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + + FT_UNUSED( pointer ); + + + pfrcmap->num_chars = face->phy_font.num_chars; + pfrcmap->chars = face->phy_font.chars; + + /* just for safety, check that the character entries are correctly */ + /* sorted in increasing character code order */ + { + FT_UInt n; + + + for ( n = 1; n < pfrcmap->num_chars; n++ ) + { + if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */ + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + + + pfrcmap->chars = NULL; + pfrcmap->num_chars = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 char_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + return mid + 1; + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 *pchar_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + Restart: + { + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + { + result = mid; + if ( result != 0 ) + { + result++; + goto Exit; + } + + char_code++; + goto Restart; + } + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + /* we didn't find it, but we have a pair just above it */ + char_code = 0; + + if ( min < pfrcmap->num_chars ) + { + gchar = pfrcmap->chars + min; + result = min; + if ( result != 0 ) + { + result++; + char_code = gchar->char_code; + } + } + } + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + pfr_cmap_class_rec = + { + sizeof ( PFR_CMapRec ), + + (FT_CMap_InitFunc) pfr_cmap_init, /* init */ + (FT_CMap_DoneFunc) pfr_cmap_done, /* done */ + (FT_CMap_CharIndexFunc)pfr_cmap_char_index, /* char_index */ + (FT_CMap_CharNextFunc) pfr_cmap_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/pfr/pfrcmap.h b/modules/freetype2/src/pfr/pfrcmap.h new file mode 100644 index 0000000000..8110f175e8 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrcmap.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * pfrcmap.h + * + * FreeType PFR cmap handling (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 PFRCMAP_H_ +#define PFRCMAP_H_ + +#include <freetype/internal/ftobjs.h> +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_chars; + PFR_Char chars; + + } PFR_CMapRec, *PFR_CMap; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec; + +FT_END_HEADER + + +#endif /* PFRCMAP_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrdrivr.c b/modules/freetype2/src/pfr/pfrdrivr.c new file mode 100644 index 0000000000..0048f52411 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrdrivr.c @@ -0,0 +1,212 @@ +/**************************************************************************** + * + * pfrdrivr.c + * + * FreeType PFR driver interface (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 <freetype/internal/ftstream.h> +#include <freetype/internal/services/svpfr.h> +#include <freetype/internal/services/svfntfmt.h> +#include "pfrdrivr.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + + + (void)pfr_face_get_kerning( face, left, right, avector ); + + /* convert from metrics to outline units when necessary */ + if ( phys->outline_resolution != phys->metrics_resolution ) + { + if ( avector->x != 0 ) + avector->x = FT_MulDiv( avector->x, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + if ( avector->y != 0 ) + avector->y = FT_MulDiv( avector->y, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + } + + return FT_Err_Ok; + } + + + /* + * PFR METRICS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_advance( FT_Face face, /* PFR_Face */ + FT_UInt gindex, + FT_Pos *anadvance ) + { + PFR_Face pfrface = (PFR_Face)face; + FT_Error error = FT_ERR( Invalid_Argument ); + + + *anadvance = 0; + + if ( !gindex ) + goto Exit; + + gindex--; + + if ( pfrface ) + { + PFR_PhyFont phys = &pfrface->phy_font; + + + if ( gindex < phys->num_chars ) + { + *anadvance = phys->chars[gindex].advance; + error = FT_Err_Ok; + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_metrics( FT_Face face, /* PFR_Face */ + FT_UInt *anoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + FT_Fixed x_scale, y_scale; + FT_Size size = pfrface->root.size; + + + if ( anoutline_resolution ) + *anoutline_resolution = phys->outline_resolution; + + if ( ametrics_resolution ) + *ametrics_resolution = phys->metrics_resolution; + + x_scale = 0x10000L; + y_scale = 0x10000L; + + if ( size ) + { + x_scale = FT_DivFix( size->metrics.x_ppem << 6, + (FT_Long)phys->metrics_resolution ); + + y_scale = FT_DivFix( size->metrics.y_ppem << 6, + (FT_Long)phys->metrics_resolution ); + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + return FT_Err_Ok; + } + + + static + const FT_Service_PfrMetricsRec pfr_metrics_service_rec = + { + pfr_get_metrics, /* get_metrics */ + pfr_face_get_kerning, /* get_kerning */ + pfr_get_advance /* get_advance */ + }; + + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pfr_services[] = + { + { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PFR }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pfr_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pfr_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pfr_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE, + + sizeof ( FT_DriverRec ), + + "pfr", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + pfr_get_service /* FT_Module_Requester get_interface */ + }, + + sizeof ( PFR_FaceRec ), + sizeof ( PFR_SizeRec ), + sizeof ( PFR_SlotRec ), + + pfr_face_init, /* FT_Face_InitFunc init_face */ + pfr_face_done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + pfr_slot_init, /* FT_Slot_InitFunc init_slot */ + pfr_slot_done, /* FT_Slot_DoneFunc done_slot */ + + pfr_slot_load, /* FT_Slot_LoadFunc load_glyph */ + + pfr_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + NULL, /* FT_Size_RequestFunc request_size */ + NULL, /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrdrivr.h b/modules/freetype2/src/pfr/pfrdrivr.h new file mode 100644 index 0000000000..da14468d42 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrdrivr.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * pfrdrivr.h + * + * High-level Type PFR driver interface (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 PFRDRIVR_H_ +#define PFRDRIVR_H_ + + +#include <freetype/internal/ftdrv.h> + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class; + +FT_END_HEADER + + +#endif /* PFRDRIVR_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrerror.h b/modules/freetype2/src/pfr/pfrerror.h new file mode 100644 index 0000000000..5dfb254d66 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrerror.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pfrerror.h + * + * PFR error codes (specification only). + * + * 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. + * + */ + + + /************************************************************************** + * + * This file is used to define the PFR error enumeration constants. + * + */ + +#ifndef PFRERROR_H_ +#define PFRERROR_H_ + +#include <freetype/ftmoderr.h> + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PFR_Err_ +#define FT_ERR_BASE FT_Mod_Err_PFR + +#include <freetype/fterrors.h> + +#endif /* PFRERROR_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrgload.c b/modules/freetype2/src/pfr/pfrgload.c new file mode 100644 index 0000000000..48cf27ec80 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrgload.c @@ -0,0 +1,849 @@ +/**************************************************************************** + * + * pfrgload.c + * + * FreeType PFR glyph loader (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 "pfrgload.h" +#include "pfrsbit.h" +#include "pfrload.h" /* for macro definitions */ +#include <freetype/internal/ftdebug.h> + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ) + { + FT_ZERO( glyph ); + + glyph->loader = loader; + + FT_GlyphLoader_Rewind( loader ); + } + + + FT_LOCAL_DEF( void ) + pfr_glyph_done( PFR_Glyph glyph ) + { + FT_Memory memory = glyph->loader->memory; + + + FT_FREE( glyph->x_control ); + glyph->y_control = NULL; + + glyph->max_xy_control = 0; +#if 0 + glyph->num_x_control = 0; + glyph->num_y_control = 0; +#endif + + FT_FREE( glyph->subs ); + + glyph->max_subs = 0; + glyph->num_subs = 0; + + glyph->loader = NULL; + glyph->path_begun = 0; + } + + + /* close current contour, if any */ + static void + pfr_glyph_close_contour( PFR_Glyph glyph ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Int last, first; + + + if ( !glyph->path_begun ) + return; + + /* compute first and last point indices in current glyph outline */ + last = outline->n_points - 1; + first = 0; + if ( outline->n_contours > 0 ) + first = outline->contours[outline->n_contours - 1]; + + /* if the last point falls on the same location as the first one */ + /* we need to delete it */ + if ( last > first ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + last; + + + if ( p1->x == p2->x && p1->y == p2->y ) + { + outline->n_points--; + last--; + } + } + + /* don't add empty contours */ + if ( last >= first ) + outline->contours[outline->n_contours++] = (short)last; + + glyph->path_begun = 0; + } + + + /* reset glyph to start the loading of a new glyph */ + static void + pfr_glyph_start( PFR_Glyph glyph ) + { + glyph->path_begun = 0; + } + + + static FT_Error + pfr_glyph_line_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); + if ( !error ) + { + FT_Int n = outline->n_points; + + + outline->points[n] = *to; + outline->tags [n] = FT_CURVE_TAG_ON; + + outline->n_points++; + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_curve_to( PFR_Glyph glyph, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); + if ( !error ) + { + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_CURVE_TAG_CUBIC; + tag[1] = FT_CURVE_TAG_CUBIC; + tag[2] = FT_CURVE_TAG_ON; + + outline->n_points = (FT_Short)( outline->n_points + 3 ); + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_move_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Error error; + + + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* indicate that a new contour has started */ + glyph->path_begun = 1; + + /* check that there is space for a new contour and a new point */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); + if ( !error ) + { + /* add new start point */ + error = pfr_glyph_line_to( glyph, to ); + } + + return error; + } + + + static void + pfr_glyph_end( PFR_Glyph glyph ) + { + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* merge the current glyph into the stack */ + FT_GlyphLoader_Add( glyph->loader ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH LOADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* load a simple glyph */ + static FT_Error + pfr_glyph_load_simple( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + FT_UInt flags, x_count, y_count, i, count, mask; + FT_Int x; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( flags & PFR_GLYPH_IS_COMPOUND ) + goto Failure; + + x_count = 0; + y_count = 0; + + if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) + { + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + x_count = count & 15; + y_count = count >> 4; + } + else + { + if ( flags & PFR_GLYPH_XCOUNT ) + { + PFR_CHECK( 1 ); + x_count = PFR_NEXT_BYTE( p ); + } + + if ( flags & PFR_GLYPH_YCOUNT ) + { + PFR_CHECK( 1 ); + y_count = PFR_NEXT_BYTE( p ); + } + } + + count = x_count + y_count; + + /* re-allocate array when necessary */ + if ( count > glyph->max_xy_control ) + { + FT_UInt new_max = FT_PAD_CEIL( count, 8 ); + + + if ( FT_RENEW_ARRAY( glyph->x_control, + glyph->max_xy_control, + new_max ) ) + goto Exit; + + glyph->max_xy_control = new_max; + } + + glyph->y_control = glyph->x_control + x_count; + + mask = 0; + x = 0; + + for ( i = 0; i < count; i++ ) + { + if ( ( i & 7 ) == 0 ) + { + PFR_CHECK( 1 ); + mask = PFR_NEXT_BYTE( p ); + } + + if ( mask & 1 ) + { + PFR_CHECK( 2 ); + x = PFR_NEXT_SHORT( p ); + } + else + { + PFR_CHECK( 1 ); + x += PFR_NEXT_BYTE( p ); + } + + glyph->x_control[i] = x; + + mask >>= 1; + } + + /* XXX: we ignore the secondary stroke and edge definitions */ + /* since we don't support native PFR hinting */ + /* */ + if ( flags & PFR_GLYPH_SINGLE_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + pfr_glyph_start( glyph ); + + /* now load a simple glyph */ + { + FT_Vector pos[4]; + FT_Vector* cur; + + + pos[0].x = pos[0].y = 0; + pos[3] = pos[0]; + + for (;;) + { + FT_UInt format, format_low, args_format = 0, args_count, n; + + + /**************************************************************** + * read instruction + */ + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + format_low = format & 15; + + switch ( format >> 4 ) + { + case 0: /* end glyph */ + FT_TRACE6(( "- end glyph" )); + args_count = 0; + break; + + case 1: /* general line operation */ + FT_TRACE6(( "- general line" )); + goto Line1; + + case 4: /* move to inside contour */ + FT_TRACE6(( "- move to inside" )); + goto Line1; + + case 5: /* move to outside contour */ + FT_TRACE6(( "- move to outside" )); + Line1: + args_format = format_low; + args_count = 1; + break; + + case 2: /* horizontal line to */ + FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + if ( format_low >= x_count ) + goto Failure; + pos[0].x = glyph->x_control[format_low]; + pos[0].y = pos[3].y; + pos[3] = pos[0]; + args_count = 0; + break; + + case 3: /* vertical line to */ + FT_TRACE6(( "- vertical line to cy.%d", format_low )); + if ( format_low >= y_count ) + goto Failure; + pos[0].x = pos[3].x; + pos[0].y = glyph->y_control[format_low]; + pos[3] = pos[0]; + args_count = 0; + break; + + case 6: /* horizontal to vertical curve */ + FT_TRACE6(( "- hv curve" )); + args_format = 0xB8E; + args_count = 3; + break; + + case 7: /* vertical to horizontal curve */ + FT_TRACE6(( "- vh curve" )); + args_format = 0xE2B; + args_count = 3; + break; + + default: /* general curve to */ + FT_TRACE6(( "- general curve" )); + args_count = 4; + args_format = format_low; + } + + /************************************************************ + * now read arguments + */ + cur = pos; + for ( n = 0; n < args_count; n++ ) + { + FT_UInt idx; + FT_Int delta; + + + /* read the X argument */ + switch ( args_format & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= x_count ) + goto Failure; + cur->x = glyph->x_control[idx]; + FT_TRACE7(( " cx#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->x = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " x.%ld", cur->x )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->x = pos[3].x + delta; + FT_TRACE7(( " dx.%d", delta )); + break; + + default: + FT_TRACE7(( " |" )); + cur->x = pos[3].x; + } + + /* read the Y argument */ + switch ( ( args_format >> 2 ) & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= y_count ) + goto Failure; + cur->y = glyph->y_control[idx]; + FT_TRACE7(( " cy#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->y = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " y.%ld", cur->y )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->y = pos[3].y + delta; + FT_TRACE7(( " dy.%d", delta )); + break; + + default: + FT_TRACE7(( " -" )); + cur->y = pos[3].y; + } + + /* read the additional format flag for the general curve */ + if ( n == 0 && args_count == 4 ) + { + PFR_CHECK( 1 ); + args_format = PFR_NEXT_BYTE( p ); + args_count--; + } + else + args_format >>= 4; + + /* save the previous point */ + pos[3] = cur[0]; + cur++; + } + + FT_TRACE7(( "\n" )); + + /************************************************************ + * finally, execute instruction + */ + switch ( format >> 4 ) + { + case 0: /* end glyph => EXIT */ + pfr_glyph_end( glyph ); + goto Exit; + + case 1: /* line operations */ + case 2: + case 3: + error = pfr_glyph_line_to( glyph, pos ); + goto Test_Error; + + case 4: /* move to inside contour */ + case 5: /* move to outside contour */ + error = pfr_glyph_move_to( glyph, pos ); + goto Test_Error; + + default: /* curve operations */ + error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); + + Test_Error: /* test error condition */ + if ( error ) + goto Exit; + } + } /* for (;;) */ + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); + goto Exit; + } + + + /* load a composite/compound glyph */ + static FT_Error + pfr_glyph_load_compound( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + PFR_SubGlyph subglyph; + FT_UInt flags, i, count, org_count; + FT_Int x_pos, y_pos; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) + goto Failure; + + count = flags & 0x3F; + + /* ignore extra items when present */ + /* */ + if ( flags & PFR_GLYPH_COMPOUND_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ + /* the PFR format is dumb, using direct file offsets to point to the */ + /* sub-glyphs (instead of glyph indices). Sigh. */ + /* */ + /* For now, we load the list of sub-glyphs into a different array */ + /* but this will prevent us from using the auto-hinter at its best */ + /* quality. */ + /* */ + org_count = glyph->num_subs; + + if ( org_count + count > glyph->max_subs ) + { + FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; + + + /* we arbitrarily limit the number of subglyphs */ + /* to avoid endless recursion */ + if ( new_max > 64 ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound:" + " too many compound glyphs components\n" )); + goto Exit; + } + + if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) + goto Exit; + + glyph->max_subs = new_max; + } + + subglyph = glyph->subs + org_count; + + for ( i = 0; i < count; i++, subglyph++ ) + { + FT_UInt format; + + + x_pos = 0; + y_pos = 0; + + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + + /* read scale when available */ + subglyph->x_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_XSCALE ) + { + PFR_CHECK( 2 ); + subglyph->x_scale = PFR_NEXT_SHORT( p ) * 16; + } + + subglyph->y_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_YSCALE ) + { + PFR_CHECK( 2 ); + subglyph->y_scale = PFR_NEXT_SHORT( p ) * 16; + } + + /* read offset */ + switch ( format & 3 ) + { + case 1: + PFR_CHECK( 2 ); + x_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + x_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + switch ( ( format >> 2 ) & 3 ) + { + case 1: + PFR_CHECK( 2 ); + y_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + y_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + subglyph->x_delta = x_pos; + subglyph->y_delta = y_pos; + + /* read glyph position and size now */ + if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) + { + PFR_CHECK( 2 ); + subglyph->gps_size = PFR_NEXT_USHORT( p ); + } + else + { + PFR_CHECK( 1 ); + subglyph->gps_size = PFR_NEXT_BYTE( p ); + } + + if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) + { + PFR_CHECK( 3 ); + subglyph->gps_offset = PFR_NEXT_ULONG( p ); + } + else + { + PFR_CHECK( 2 ); + subglyph->gps_offset = PFR_NEXT_USHORT( p ); + } + + glyph->num_subs++; + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_glyph_load_rec( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + FT_Error error; + FT_Byte* p; + FT_Byte* limit; + + + if ( FT_STREAM_SEEK( gps_offset + offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + limit = p + size; + + if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) + { + FT_UInt n, old_count, count; + FT_GlyphLoader loader = glyph->loader; + FT_Outline* base = &loader->base.outline; + + + old_count = glyph->num_subs; + + /* this is a compound glyph - load it */ + error = pfr_glyph_load_compound( glyph, p, limit ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + count = glyph->num_subs - old_count; + + FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n", + count, + count == 1 ? "" : "s", + offset )); + + /* now, load each individual glyph */ + for ( n = 0; n < count; n++ ) + { + FT_Int i, old_points, num_points; + PFR_SubGlyph subglyph; + + + FT_TRACE4(( " subglyph %d:\n", n )); + + subglyph = glyph->subs + old_count + n; + old_points = base->n_points; + + error = pfr_glyph_load_rec( glyph, stream, gps_offset, + subglyph->gps_offset, + subglyph->gps_size ); + if ( error ) + break; + + /* note that `glyph->subs' might have been re-allocated */ + subglyph = glyph->subs + old_count + n; + num_points = base->n_points - old_points; + + /* translate and eventually scale the new glyph points */ + if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) + { + FT_Vector* vec = base->points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + + subglyph->x_delta; + vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + + subglyph->y_delta; + } + } + else + { + FT_Vector* vec = loader->base.outline.points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x += subglyph->x_delta; + vec->y += subglyph->y_delta; + } + } + + /* proceed to next sub-glyph */ + } + + FT_TRACE4(( "end compound glyph with %d element%s\n", + count, + count == 1 ? "" : "s" )); + } + else + { + FT_TRACE4(( "simple glyph (offset %lu)\n", offset )); + + /* load a simple glyph */ + error = pfr_glyph_load_simple( glyph, p, limit ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + /* initialize glyph loader */ + FT_GlyphLoader_Rewind( glyph->loader ); + + glyph->num_subs = 0; + + /* load the glyph, recursively when needed */ + return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); + } + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrgload.h b/modules/freetype2/src/pfr/pfrgload.h new file mode 100644 index 0000000000..92a59bc5db --- /dev/null +++ b/modules/freetype2/src/pfr/pfrgload.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * pfrgload.h + * + * FreeType PFR glyph loader (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 PFRGLOAD_H_ +#define PFRGLOAD_H_ + +#include "pfrtypes.h" + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ); + + FT_LOCAL( void ) + pfr_glyph_done( PFR_Glyph glyph ); + + + FT_LOCAL( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ); + + +FT_END_HEADER + + +#endif /* PFRGLOAD_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrload.c b/modules/freetype2/src/pfr/pfrload.c new file mode 100644 index 0000000000..856a5942f5 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrload.c @@ -0,0 +1,1062 @@ +/**************************************************************************** + * + * pfrload.c + * + * FreeType PFR loader (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 "pfrload.h" +#include <freetype/internal/ftdebug.h> +#include <freetype/internal/ftstream.h> + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /* + * The overall structure of a PFR file is as follows. + * + * PFR header + * 58 bytes (contains nPhysFonts) + * + * Logical font directory (size at most 2^16 bytes) + * 2 bytes (nLogFonts) + * + nLogFonts * 5 bytes + * + * ==> nLogFonts <= 13106 + * + * Logical font section (size at most 2^24 bytes) + * nLogFonts * logFontRecord + * + * logFontRecord (size at most 2^16 bytes) + * 12 bytes (fontMatrix) + * + 1 byte (flags) + * + 0-5 bytes (depending on `flags') + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + 5 bytes (physical font info) + * + 0-1 bytes (depending on PFR header) + * + * ==> minimum size 18 bytes + * + * Physical font section (size at most 2^24 bytes) + * nPhysFonts * (physFontRecord + * + nBitmapSizes * nBmapChars * bmapCharRecord) + * + * physFontRecord (size at most 2^24 bytes) + * 14 bytes (font info) + * + 1 byte (flags) + * + 0-2 (depending on `flags') + * + 0-? (structure too complicated to be shown here; depending on + * `flags'; contains `nBitmapSizes' and `nBmapChars') + * + 3 bytes (nAuxBytes) + * + nAuxBytes + * + 1 byte (nBlueValues) + * + 2 * nBlueValues + * + 6 bytes (hinting data) + * + 2 bytes (nCharacters) + * + nCharacters * (4-10 bytes) (depending on `flags') + * + * ==> minimum size 27 bytes + * + * bmapCharRecord + * 4-7 bytes + * + * Glyph program strings (three possible types: simpleGps, compoundGps, + * and bitmapGps; size at most 2^24 bytes) + * simpleGps (size at most 2^16 bytes) + * 1 byte (flags) + * 1-2 bytes (n[XY]orus, depending on `flags') + * 0-(64+512*2) = 0-1088 bytes (depending on `n[XY]orus') + * 0-? (structure too complicated to be shown here; depending on + * `flags') + * 1-? glyph data (faintly resembling PS Type 1 charstrings) + * + * ==> minimum size 3 bytes + * + * compoundGps (size at most 2^16 bytes) + * 1 byte (nElements <= 63, flags) + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + nElements * (6-14 bytes) + * + * bitmapGps (size at most 2^16 bytes) + * 1 byte (flags) + * 3-13 bytes (position info, depending on `flags') + * 0-? bitmap data + * + * ==> minimum size 4 bytes + * + * PFR trailer + * 8 bytes + * + * + * ==> minimum size of a valid PFR: + * 58 (header) + * + 2 (nLogFonts) + * + 27 (1 physFontRecord) + * + 8 (trailer) + * ----- + * 95 bytes + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** EXTRA ITEMS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ) + { + return pfr_extra_items_parse( pp, limit, NULL, NULL ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* p = *pp; + FT_UInt num_items, item_type, item_size; + + + PFR_CHECK( 1 ); + num_items = PFR_NEXT_BYTE( p ); + + for ( ; num_items > 0; num_items-- ) + { + PFR_CHECK( 2 ); + item_size = PFR_NEXT_BYTE( p ); + item_type = PFR_NEXT_BYTE( p ); + + PFR_CHECK( item_size ); + + if ( item_list ) + { + PFR_ExtraItem extra = item_list; + + + for ( extra = item_list; extra->parser != NULL; extra++ ) + { + if ( extra->type == item_type ) + { + error = extra->parser( p, p + item_size, item_data ); + if ( error ) + goto Exit; + + break; + } + } + } + + p += item_size; + } + + Exit: + *pp = p; + return error; + + Too_Short: + FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR HEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static const FT_Frame_Field pfr_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PFR_HeaderRec + + FT_FRAME_START( 58 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_USHORT( version ), + FT_FRAME_USHORT( signature2 ), + FT_FRAME_USHORT( header_size ), + + FT_FRAME_USHORT( log_dir_size ), + FT_FRAME_USHORT( log_dir_offset ), + + FT_FRAME_USHORT( log_font_max_size ), + FT_FRAME_UOFF3 ( log_font_section_size ), + FT_FRAME_UOFF3 ( log_font_section_offset ), + + FT_FRAME_USHORT( phy_font_max_size ), + FT_FRAME_UOFF3 ( phy_font_section_size ), + FT_FRAME_UOFF3 ( phy_font_section_offset ), + + FT_FRAME_USHORT( gps_max_size ), + FT_FRAME_UOFF3 ( gps_section_size ), + FT_FRAME_UOFF3 ( gps_section_offset ), + + FT_FRAME_BYTE ( max_blue_values ), + FT_FRAME_BYTE ( max_x_orus ), + FT_FRAME_BYTE ( max_y_orus ), + + FT_FRAME_BYTE ( phy_font_max_size_high ), + FT_FRAME_BYTE ( color_flags ), + + FT_FRAME_UOFF3 ( bct_max_size ), + FT_FRAME_UOFF3 ( bct_set_max_size ), + FT_FRAME_UOFF3 ( phy_bct_set_max_size ), + + FT_FRAME_USHORT( num_phy_fonts ), + FT_FRAME_BYTE ( max_vert_stem_snap ), + FT_FRAME_BYTE ( max_horz_stem_snap ), + FT_FRAME_USHORT( max_chars ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ) + { + FT_Error error; + + + /* read header directly */ + if ( !FT_STREAM_SEEK( 0 ) && + !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) ) + { + /* make a few adjustments to the header */ + header->phy_font_max_size += + (FT_UInt32)header->phy_font_max_size_high << 16; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + pfr_header_check( PFR_Header header ) + { + FT_Bool result = 1; + + + /* check signature and header size */ + if ( header->signature != 0x50465230L || /* "PFR0" */ + header->version > 4 || + header->header_size < 58 || + header->signature2 != 0x0D0A ) /* CR/LF */ + result = 0; + + return result; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR LOGICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 section_offset, + FT_Long *acount ) + { + FT_Error error; + FT_UInt count; + FT_UInt result = 0; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( count ) ) + goto Exit; + + /* check maximum value and a rough minimum size: */ + /* - no more than 13106 log fonts */ + /* - we need 5 bytes for a log header record */ + /* - we need at least 18 bytes for a log font record */ + /* - the overall size is at least 95 bytes plus the */ + /* log header and log font records */ + if ( count > ( ( 1 << 16 ) - 2 ) / 5 || + 2 + count * 5 >= stream->size - section_offset || + 95 + count * ( 5 + 18 ) >= stream->size ) + { + FT_ERROR(( "pfr_log_font_count:" + " invalid number of logical fonts\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + result = count; + + Exit: + *acount = (FT_Long)result; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt idx, + FT_UInt32 section_offset, + FT_Bool size_increment ) + { + FT_UInt num_log_fonts; + FT_UInt flags; + FT_UInt32 offset; + FT_UInt32 size; + FT_Error error; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( num_log_fonts ) ) + goto Exit; + + if ( idx >= num_log_fonts ) + return FT_THROW( Invalid_Argument ); + + if ( FT_STREAM_SKIP( idx * 5 ) || + FT_READ_USHORT( size ) || + FT_READ_UOFF3 ( offset ) ) + goto Exit; + + /* save logical font size and offset */ + log_font->size = size; + log_font->offset = offset; + + /* now, check the rest of the table before loading it */ + { + FT_Byte* p; + FT_Byte* limit; + FT_UInt local; + + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 13 ); + + log_font->matrix[0] = PFR_NEXT_LONG( p ); + log_font->matrix[1] = PFR_NEXT_LONG( p ); + log_font->matrix[2] = PFR_NEXT_LONG( p ); + log_font->matrix[3] = PFR_NEXT_LONG( p ); + + flags = PFR_NEXT_BYTE( p ); + + local = 0; + if ( flags & PFR_LOG_STROKE ) + { + local++; + if ( flags & PFR_LOG_2BYTE_STROKE ) + local++; + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + local += 3; + } + if ( flags & PFR_LOG_BOLD ) + { + local++; + if ( flags & PFR_LOG_2BYTE_BOLD ) + local++; + } + + PFR_CHECK( local ); + + if ( flags & PFR_LOG_STROKE ) + { + log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + log_font->miter_limit = PFR_NEXT_LONG( p ); + } + + if ( flags & PFR_LOG_BOLD ) + log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( flags & PFR_LOG_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Fail; + } + + PFR_CHECK( 5 ); + log_font->phys_size = PFR_NEXT_USHORT( p ); + log_font->phys_offset = PFR_NEXT_ULONG( p ); + if ( size_increment ) + { + PFR_CHECK( 1 ); + log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16; + } + } + + Fail: + FT_FRAME_EXIT(); + + Exit: + return error; + + Too_Short: + FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR PHYSICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + /* load bitmap strikes lists */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = FT_Err_Ok; + + + PFR_CHECK( 5 ); + + p += 3; /* skip bctSize */ + flags0 = PFR_NEXT_BYTE( p ); + count = PFR_NEXT_BYTE( p ); + + /* re-allocate when needed */ + if ( phy_font->num_strikes + count > phy_font->max_strikes ) + { + FT_UInt new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 ); + + + if ( FT_RENEW_ARRAY( phy_font->strikes, + phy_font->num_strikes, + new_max ) ) + goto Exit; + + phy_font->max_strikes = new_max; + } + + size1 = 1 + 1 + 1 + 2 + 2 + 1; + if ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + size1++; + + strike = phy_font->strikes + phy_font->num_strikes; + + PFR_CHECK( count * size1 ); + + for ( n = 0; n < count; n++, strike++ ) + { + strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->flags = PFR_NEXT_BYTE( p ); + + strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + } + + phy_font->num_strikes += count; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_bitmap_info:" + " invalid bitmap info table\n" )); + goto Exit; + } + + + /* Load font ID. This is a so-called `unique' name that is rather + * long and descriptive (like `Tiresias ScreenFont v7.51'). + * + * Note that a PFR font's family name is contained in an *undocumented* + * string of the `auxiliary data' portion of a physical font record. This + * may also contain the `real' style name! + * + * If no family name is present, the font ID is used instead for the + * family. + */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_UInt len = (FT_UInt)( limit - p ); + + + if ( phy_font->font_id ) + goto Exit; + + if ( FT_QALLOC( phy_font->font_id, len + 1 ) ) + goto Exit; + + /* copy font ID name, and terminate it for safety */ + FT_MEM_COPY( phy_font->font_id, p, len ); + phy_font->font_id[len] = 0; + + Exit: + return error; + } + + + /* load stem snap tables */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_UInt count, num_vert, num_horz; + FT_Int* snaps = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( phy_font->vertical.stem_snaps ) + goto Exit; + + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + + num_vert = count & 15; + num_horz = count >> 4; + count = num_vert + num_horz; + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( snaps, count ) ) + goto Exit; + + phy_font->vertical.stem_snaps = snaps; + phy_font->horizontal.stem_snaps = snaps + num_vert; + + for ( ; count > 0; count--, snaps++ ) + *snaps = FT_NEXT_SHORT( p ); + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_stem_snaps:" + " invalid stem snaps table\n" )); + goto Exit; + } + + + /* load kerning pair data */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + PFR_KernItem item = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( FT_NEW( item ) ) + goto Exit; + + PFR_CHECK( 4 ); + + item->pair_count = PFR_NEXT_BYTE( p ); + item->base_adj = PFR_NEXT_SHORT( p ); + item->flags = PFR_NEXT_BYTE( p ); + item->offset = phy_font->offset + + (FT_Offset)( p - phy_font->cursor ); + +#ifndef PFR_CONFIG_NO_CHECKS + item->pair_size = 3; + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + item->pair_size += 2; + + if ( item->flags & PFR_KERN_2BYTE_ADJ ) + item->pair_size += 1; + + PFR_CHECK( item->pair_count * item->pair_size ); +#endif + + /* load first and last pairs into the item to speed up */ + /* lookup later... */ + if ( item->pair_count > 0 ) + { + FT_UInt char1, char2; + FT_Byte* q; + + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + { + q = p; + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + else + { + q = p; + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + + /* add new item to the current list */ + item->next = NULL; + *phy_font->kern_items_tail = item; + phy_font->kern_items_tail = &item->next; + phy_font->num_kern_pairs += item->pair_count; + } + else + { + /* empty item! */ + FT_FREE( item ); + } + + Exit: + return error; + + Too_Short: + FT_FREE( item ); + + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_kerning_pairs:" + " invalid kerning pairs table\n" )); + goto Exit; + } + + + static const PFR_ExtraItemRec pfr_phy_font_extra_items[] = + { + { 1, pfr_extra_item_load_bitmap_info }, + { 2, pfr_extra_item_load_font_id }, + { 3, pfr_extra_item_load_stem_snaps }, + { 4, pfr_extra_item_load_kerning_pairs }, + { 0, NULL } + }; + + + /* + * Load a name from the auxiliary data. Since this extracts undocumented + * strings from the font file, we need to be careful here. + */ + static FT_Error + pfr_aux_name_load( FT_Byte* p, + FT_UInt len, + FT_Memory memory, + FT_String* *astring ) + { + FT_Error error = FT_Err_Ok; + FT_String* result = NULL; + FT_UInt n, ok; + + + if ( *astring ) + FT_FREE( *astring ); + + if ( len > 0 && p[len - 1] == 0 ) + len--; + + /* check that each character is ASCII */ + /* for making sure not to load garbage */ + ok = ( len > 0 ); + for ( n = 0; n < len; n++ ) + if ( p[n] < 32 || p[n] > 127 ) + { + ok = 0; + break; + } + + if ( ok ) + { + if ( FT_QALLOC( result, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( result, p, len ); + result[len] = 0; + } + + Exit: + *astring = result; + return error; + } + + + FT_LOCAL_DEF( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ) + { + FT_FREE( phy_font->font_id ); + FT_FREE( phy_font->family_name ); + FT_FREE( phy_font->style_name ); + + FT_FREE( phy_font->vertical.stem_snaps ); + phy_font->vertical.num_stem_snaps = 0; + + phy_font->horizontal.stem_snaps = NULL; + phy_font->horizontal.num_stem_snaps = 0; + + FT_FREE( phy_font->strikes ); + phy_font->num_strikes = 0; + phy_font->max_strikes = 0; + + FT_FREE( phy_font->chars ); + phy_font->num_chars = 0; + phy_font->chars_offset = 0; + + FT_FREE( phy_font->blue_values ); + phy_font->num_blue_values = 0; + + { + PFR_KernItem item, next; + + + item = phy_font->kern_items; + while ( item ) + { + next = item->next; + FT_FREE( item ); + item = next; + } + phy_font->kern_items = NULL; + phy_font->kern_items_tail = NULL; + } + + phy_font->num_kern_pairs = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt flags; + FT_ULong num_aux; + FT_Byte* p; + FT_Byte* limit; + + + phy_font->memory = memory; + phy_font->offset = offset; + + phy_font->kern_items = NULL; + phy_font->kern_items_tail = &phy_font->kern_items; + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + phy_font->cursor = stream->cursor; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 15 ); + phy_font->font_ref_number = PFR_NEXT_USHORT( p ); + phy_font->outline_resolution = PFR_NEXT_USHORT( p ); + phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); + phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); + phy_font->flags = flags = PFR_NEXT_BYTE( p ); + + if ( !phy_font->outline_resolution || + !phy_font->metrics_resolution ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid resolution\n" )); + goto Fail; + } + + /* get the standard advance for non-proportional fonts */ + if ( !( flags & PFR_PHY_PROPORTIONAL ) ) + { + PFR_CHECK( 2 ); + phy_font->standard_advance = PFR_NEXT_SHORT( p ); + } + + /* load the extra items when present */ + if ( flags & PFR_PHY_EXTRA_ITEMS ) + { + error = pfr_extra_items_parse( &p, limit, + pfr_phy_font_extra_items, phy_font ); + if ( error ) + goto Fail; + } + + /* In certain fonts, the auxiliary bytes contain interesting */ + /* information. These are not in the specification but can be */ + /* guessed by looking at the content of a few 'PFR0' fonts. */ + PFR_CHECK( 3 ); + num_aux = PFR_NEXT_ULONG( p ); + + if ( num_aux > 0 ) + { + FT_Byte* q = p; + FT_Byte* q2; + + + PFR_CHECK_SIZE( num_aux ); + p += num_aux; + + while ( num_aux > 0 ) + { + FT_UInt length, type; + + + if ( q + 4 > p ) + break; + + length = PFR_NEXT_USHORT( q ); + if ( length < 4 || length > num_aux ) + break; + + q2 = q + length - 2; + type = PFR_NEXT_USHORT( q ); + + switch ( type ) + { + case 1: + /* this seems to correspond to the font's family name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->family_name ); + if ( error ) + goto Exit; + break; + + case 2: + if ( q + 32 > q2 ) + break; + + q += 10; + phy_font->ascent = PFR_NEXT_SHORT( q ); + phy_font->descent = PFR_NEXT_SHORT( q ); + phy_font->leading = PFR_NEXT_SHORT( q ); + break; + + case 3: + /* this seems to correspond to the font's style name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->style_name ); + if ( error ) + goto Exit; + break; + + default: + ; + } + + q = q2; + num_aux -= length; + } + } + + /* read the blue values */ + { + FT_UInt n, count; + + + PFR_CHECK( 1 ); + phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( phy_font->blue_values, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); + } + + PFR_CHECK( 8 ); + phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); + phy_font->blue_scale = PFR_NEXT_BYTE( p ); + + phy_font->vertical.standard = PFR_NEXT_USHORT( p ); + phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); + + /* read the character descriptors */ + { + FT_UInt n, count, Size; + + + phy_font->num_chars = count = PFR_NEXT_USHORT( p ); + phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor ); + + if ( !phy_font->num_chars ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: no glyphs\n" )); + goto Fail; + } + + Size = 1 + 1 + 2; + if ( flags & PFR_PHY_2BYTE_CHARCODE ) + Size += 1; + + if ( flags & PFR_PHY_PROPORTIONAL ) + Size += 2; + + if ( flags & PFR_PHY_ASCII_CODE ) + Size += 1; + + if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + Size += 1; + + if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + Size += 1; + + PFR_CHECK_SIZE( count * Size ); + + if ( FT_QNEW_ARRAY( phy_font->chars, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + PFR_Char cur = &phy_font->chars[n]; + + + cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) + ? PFR_NEXT_SHORT( p ) + : phy_font->standard_advance; + +#if 0 + cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) + ? PFR_NEXT_BYTE( p ) + : 0; +#else + if ( flags & PFR_PHY_ASCII_CODE ) + p += 1; +#endif + cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + } + } + + /* that's it! */ + + Fail: + FT_FRAME_EXIT(); + + /* save position of bitmap info */ + phy_font->bct_offset = FT_STREAM_POS(); + phy_font->cursor = NULL; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); + goto Fail; + } + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrload.h b/modules/freetype2/src/pfr/pfrload.h new file mode 100644 index 0000000000..d7b20a4572 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrload.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * pfrload.h + * + * FreeType PFR loader (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 PFRLOAD_H_ +#define PFRLOAD_H_ + +#include "pfrobjs.h" +#include <freetype/internal/ftstream.h> + + +FT_BEGIN_HEADER + + /* some size checks should be always done (mainly to prevent */ + /* excessive allocation for malformed data), ... */ +#define PFR_CHECK_SIZE( x ) do \ + { \ + if ( p + (x) > limit ) \ + goto Too_Short; \ + } while ( 0 ) + + /* ... and some only if intensive checking is explicitly requested */ +#ifdef PFR_CONFIG_NO_CHECKS +#define PFR_CHECK( x ) do { } while ( 0 ) +#else +#define PFR_CHECK PFR_CHECK_SIZE +#endif + +#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p ) +#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p ) +#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p ) +#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p ) +#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p ) +#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p ) + + + /* handling extra items */ + + typedef FT_Error + (*PFR_ExtraItem_ParseFunc)( FT_Byte* p, + FT_Byte* limit, + FT_Pointer data ); + + typedef struct PFR_ExtraItemRec_ + { + FT_UInt type; + PFR_ExtraItem_ParseFunc parser; + + } PFR_ExtraItemRec; + + typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem; + + + FT_LOCAL( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ); + + FT_LOCAL( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ); + + + /* load a PFR header */ + FT_LOCAL( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ); + + /* check a PFR header */ + FT_LOCAL( FT_Bool ) + pfr_header_check( PFR_Header header ); + + + /* return number of logical fonts in this file */ + FT_LOCAL( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 log_section_offset, + FT_Long *acount ); + + /* load a pfr logical font entry */ + FT_LOCAL( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt face_index, + FT_UInt32 section_offset, + FT_Bool size_increment ); + + + /* load a physical font entry */ + FT_LOCAL( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ); + + /* finalize a physical font */ + FT_LOCAL( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ); + + /* */ + +FT_END_HEADER + +#endif /* PFRLOAD_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrobjs.c b/modules/freetype2/src/pfr/pfrobjs.c new file mode 100644 index 0000000000..8ef17c6636 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrobjs.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * pfrobjs.c + * + * FreeType PFR object methods (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 "pfrobjs.h" +#include "pfrload.h" +#include "pfrgload.h" +#include "pfrcmap.h" +#include "pfrsbit.h" +#include <freetype/ftoutln.h> +#include <freetype/internal/ftdebug.h> +#include <freetype/internal/ftcalc.h> +#include <freetype/ttnameid.h> + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE OBJECT METHODS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + pfr_face_done( FT_Face pfrface ) /* PFR_Face */ + { + PFR_Face face = (PFR_Face)pfrface; + FT_Memory memory; + + + if ( !face ) + return; + + memory = pfrface->memory; + + /* we don't want dangling pointers */ + pfrface->family_name = NULL; + pfrface->style_name = NULL; + + /* finalize the physical font record */ + pfr_phy_font_done( &face->phy_font, memory ); + + /* no need to finalize the logical font or the header */ + FT_FREE( pfrface->available_sizes ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face pfrface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "PFR driver\n" )); + + /* load the header and check it */ + error = pfr_header_load( &face->header, stream ); + if ( error ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( !pfr_header_check( &face->header ) ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* check face index */ + { + FT_Long num_faces; + + + error = pfr_log_font_count( stream, + face->header.log_dir_offset, + &num_faces ); + if ( error ) + goto Exit; + + pfrface->num_faces = num_faces; + } + + if ( face_index < 0 ) + goto Exit; + + if ( ( face_index & 0xFFFF ) >= pfrface->num_faces ) + { + FT_ERROR(( "pfr_face_init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* load the face */ + error = pfr_log_font_load( + &face->log_font, + stream, + (FT_UInt)( face_index & 0xFFFF ), + face->header.log_dir_offset, + FT_BOOL( face->header.phy_font_max_size_high ) ); + if ( error ) + goto Exit; + + /* load the physical font descriptor */ + error = pfr_phy_font_load( &face->phy_font, stream, + face->log_font.phys_offset, + face->log_font.phys_size ); + if ( error ) + goto Exit; + + /* set up all root face fields */ + { + PFR_PhyFont phy_font = &face->phy_font; + + + pfrface->face_index = face_index & 0xFFFF; + pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1; + + pfrface->face_flags |= FT_FACE_FLAG_SCALABLE; + + /* if gps_offset == 0 for all characters, we */ + /* assume that the font only contains bitmaps */ + { + FT_UInt nn; + + + for ( nn = 0; nn < phy_font->num_chars; nn++ ) + if ( phy_font->chars[nn].gps_offset != 0 ) + break; + + if ( nn == phy_font->num_chars ) + { + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + else + { + FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + } + + if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( phy_font->flags & PFR_PHY_VERTICAL ) + pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; + else + pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + + if ( phy_font->num_kern_pairs > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + + /* If no family name was found in the `undocumented' auxiliary + * data, use the font ID instead. This sucks but is better than + * nothing. + */ + pfrface->family_name = phy_font->family_name; + if ( !pfrface->family_name ) + pfrface->family_name = phy_font->font_id; + + /* note that the style name can be NULL in certain PFR fonts, + * probably meaning `Regular' + */ + pfrface->style_name = phy_font->style_name; + + pfrface->num_fixed_sizes = 0; + pfrface->available_sizes = NULL; + + pfrface->bbox = phy_font->bbox; + pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; + pfrface->ascender = (FT_Short) phy_font->bbox.yMax; + pfrface->descender = (FT_Short) phy_font->bbox.yMin; + + pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); + if ( pfrface->height < pfrface->ascender - pfrface->descender ) + pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender ); + + if ( phy_font->num_strikes > 0 ) + { + FT_UInt n, count = phy_font->num_strikes; + FT_Bitmap_Size* size; + PFR_Strike strike; + FT_Memory memory = pfrface->memory; + + + if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) ) + goto Exit; + + size = pfrface->available_sizes; + strike = phy_font->strikes; + for ( n = 0; n < count; n++, size++, strike++ ) + { + size->height = (FT_Short)strike->y_ppm; + size->width = (FT_Short)strike->x_ppm; + size->size = (FT_Pos)( strike->y_ppm << 6 ); + size->x_ppem = (FT_Pos)( strike->x_ppm << 6 ); + size->y_ppem = (FT_Pos)( strike->y_ppm << 6 ); + } + pfrface->num_fixed_sizes = (FT_Int)count; + } + + /* now compute maximum advance width */ + if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; + else + { + FT_Int max = 0; + FT_UInt count = phy_font->num_chars; + PFR_Char gchar = phy_font->chars; + + + for ( ; count > 0; count--, gchar++ ) + { + if ( max < gchar->advance ) + max = gchar->advance; + } + + pfrface->max_advance_width = (FT_Short)max; + } + + pfrface->max_advance_height = pfrface->height; + + pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); + pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); + + /* create charmap */ + { + FT_CharMapRec charmap; + + + charmap.face = pfrface; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); + } + + /* check whether we have loaded any kerning pairs */ + if ( phy_font->num_kern_pairs ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SLOT OBJECT METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + FT_GlyphLoader loader = pfrslot->internal->loader; + + + pfr_glyph_init( &slot->glyph, loader ); + + return 0; + } + + + FT_LOCAL_DEF( void ) + pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + + + pfr_glyph_done( &slot->glyph ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ + FT_Size pfrsize, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + PFR_Size size = (PFR_Size)pfrsize; + FT_Error error; + PFR_Face face = (PFR_Face)pfrslot->face; + PFR_Char gchar; + FT_Outline* outline = &pfrslot->outline; + FT_ULong gps_offset; + + + FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); + + if ( gindex > 0 ) + gindex--; + + if ( !face || gindex >= face->phy_font.num_chars ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* try to load an embedded bitmap */ + if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) ) + { + error = pfr_slot_load_bitmap( + slot, + size, + gindex, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + if ( !error ) + goto Exit; + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + gchar = face->phy_font.chars + gindex; + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; + outline->n_points = 0; + outline->n_contours = 0; + gps_offset = face->header.gps_section_offset; + + /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ + error = pfr_glyph_load( &slot->glyph, face->root.stream, + gps_offset, gchar->gps_offset, gchar->gps_size ); + + if ( !error ) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &pfrslot->metrics; + FT_Pos advance; + FT_UInt em_metrics, em_outline; + FT_Bool scaling; + + + scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + + /* copy outline data */ + *outline = slot->glyph.loader->base.outline; + + outline->flags &= ~FT_OUTLINE_OWNER; + outline->flags |= FT_OUTLINE_REVERSE_FILL; + + if ( pfrsize->metrics.y_ppem < 24 ) + outline->flags |= FT_OUTLINE_HIGH_PRECISION; + + /* compute the advance vector */ + metrics->horiAdvance = 0; + metrics->vertAdvance = 0; + + advance = gchar->advance; + em_metrics = face->phy_font.metrics_resolution; + em_outline = face->phy_font.outline_resolution; + + if ( em_metrics != em_outline ) + advance = FT_MulDiv( advance, + (FT_Long)em_outline, + (FT_Long)em_metrics ); + + if ( face->phy_font.flags & PFR_PHY_VERTICAL ) + metrics->vertAdvance = advance; + else + metrics->horiAdvance = advance; + + pfrslot->linearHoriAdvance = metrics->horiAdvance; + pfrslot->linearVertAdvance = metrics->vertAdvance; + + /* make up vertical metrics(?) */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + +#if 0 /* some fonts seem to be broken here! */ + + /* Apply the font matrix, if any. */ + /* TODO: Test existing fonts with unusual matrix */ + /* whether we have to adjust Units per EM. */ + { + FT_Matrix font_matrix; + + + font_matrix.xx = face->log_font.matrix[0] << 8; + font_matrix.yx = face->log_font.matrix[1] << 8; + font_matrix.xy = face->log_font.matrix[2] << 8; + font_matrix.yy = face->log_font.matrix[3] << 8; + + FT_Outline_Transform( outline, &font_matrix ); + } +#endif + + /* scale when needed */ + if ( scaling ) + { + FT_Int n; + FT_Fixed x_scale = pfrsize->metrics.x_scale; + FT_Fixed y_scale = pfrsize->metrics.y_scale; + FT_Vector* vec = outline->points; + + + /* scale outline points */ + for ( n = 0; n < outline->n_points; n++, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* scale the advance */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the rest of the metrics */ + FT_Outline_Get_CBox( outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax - metrics->height; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** KERNING METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = FT_Err_Ok; + PFR_PhyFont phy_font = &face->phy_font; + FT_UInt32 code1, code2, pair; + + + kerning->x = 0; + kerning->y = 0; + + /* PFR indexing skips .notdef, which becomes UINT_MAX */ + glyph1--; + glyph2--; + + /* check the array bounds, .notdef is automatically out */ + if ( glyph1 >= phy_font->num_chars || + glyph2 >= phy_font->num_chars ) + goto Exit; + + /* convert glyph indices to character codes */ + code1 = phy_font->chars[glyph1].char_code; + code2 = phy_font->chars[glyph2].char_code; + pair = PFR_KERN_INDEX( code1, code2 ); + + /* now search the list of kerning items */ + { + PFR_KernItem item = phy_font->kern_items; + FT_Stream stream = pfrface->stream; + + + for ( ; item; item = item->next ) + { + if ( pair >= item->pair1 && pair <= item->pair2 ) + goto FoundPair; + } + goto Exit; + + FoundPair: /* we found an item, now parse it and find the value if any */ + if ( FT_STREAM_SEEK( item->offset ) || + FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) + goto Exit; + + { + FT_UInt count = item->pair_count; + FT_UInt size = item->pair_size; + FT_UInt power = 1 << FT_MSB( count ); + FT_UInt probe = power * size; + FT_UInt extra = count - power; + FT_Byte* base = stream->cursor; + FT_Bool twobytes = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR ); + FT_Bool twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ ); + FT_Byte* p; + FT_UInt32 cpair; + + + if ( extra > 0 ) + { + p = base + extra * size; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + { + if ( twobyte_adj ) + p += 2; + else + p++; + base = p; + } + } + + while ( probe > size ) + { + probe >>= 1; + p = base + probe; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + base += probe; + } + + p = base; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + { + FT_Int value; + + + Found: + if ( twobyte_adj ) + value = FT_PEEK_SHORT( p ); + else + value = p[0]; + + kerning->x = item->base_adj + value; + } + } + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrobjs.h b/modules/freetype2/src/pfr/pfrobjs.h new file mode 100644 index 0000000000..fcf8c38122 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrobjs.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * + * pfrobjs.h + * + * FreeType PFR object methods (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 PFROBJS_H_ +#define PFROBJS_H_ + +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_FaceRec_* PFR_Face; + + typedef struct PFR_SizeRec_* PFR_Size; + + typedef struct PFR_SlotRec_* PFR_Slot; + + + typedef struct PFR_FaceRec_ + { + FT_FaceRec root; + PFR_HeaderRec header; + PFR_LogFontRec log_font; + PFR_PhyFontRec phy_font; + + } PFR_FaceRec; + + + typedef struct PFR_SizeRec_ + { + FT_SizeRec root; + + } PFR_SizeRec; + + + typedef struct PFR_SlotRec_ + { + FT_GlyphSlotRec root; + PFR_GlyphRec glyph; + + } PFR_SlotRec; + + + FT_LOCAL( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face face, /* PFR_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + pfr_face_done( FT_Face face ); /* PFR_Face */ + + + FT_LOCAL( FT_Error ) + pfr_face_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + + FT_LOCAL( FT_Error ) + pfr_slot_init( FT_GlyphSlot slot ); /* PFR_Slot */ + + FT_LOCAL( void ) + pfr_slot_done( FT_GlyphSlot slot ); /* PFR_Slot */ + + + FT_LOCAL( FT_Error ) + pfr_slot_load( FT_GlyphSlot slot, /* PFR_Slot */ + FT_Size size, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* PFROBJS_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrsbit.c b/modules/freetype2/src/pfr/pfrsbit.c new file mode 100644 index 0000000000..46a988e8e3 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrsbit.c @@ -0,0 +1,813 @@ +/**************************************************************************** + * + * pfrsbit.c + * + * FreeType PFR bitmap loader (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 "pfrsbit.h" +#include "pfrload.h" +#include <freetype/internal/ftdebug.h> +#include <freetype/internal/ftstream.h> + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR BIT WRITER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PFR_BitWriter_ + { + FT_Byte* line; /* current line start */ + FT_Int pitch; /* line size in bytes */ + FT_UInt width; /* width in pixels/bits */ + FT_UInt rows; /* number of remaining rows to scan */ + FT_UInt total; /* total number of bits to draw */ + + } PFR_BitWriterRec, *PFR_BitWriter; + + + static void + pfr_bitwriter_init( PFR_BitWriter writer, + FT_Bitmap* target, + FT_Bool decreasing ) + { + writer->line = target->buffer; + writer->pitch = target->pitch; + writer->width = target->width; + writer->rows = target->rows; + writer->total = writer->width * writer->rows; + + if ( !decreasing ) + { + writer->line += writer->pitch * (FT_Int)( target->rows - 1 ); + writer->pitch = -writer->pitch; + } + } + + + static void + pfr_bitwriter_decode_bytes( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt val = 0; + FT_UInt c = 0; + + + n = (FT_UInt)( limit - p ) * 8; + if ( n > writer->total ) + n = writer->total; + + reload = n & 7; + + for ( ; n > 0; n-- ) + { + if ( ( n & 7 ) == reload ) + val = *p++; + + if ( val & 0x80 ) + c |= mask; + + val <<= 1; + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte)c; + } + + + static void + pfr_bitwriter_decode_rle1( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count, counts[2]; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + counts[0] = 0; + counts[1] = 0; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( phase ) + { + FT_Int v; + + + if ( p >= limit ) + break; + + v = *p++; + counts[0] = v >> 4; + counts[1] = v & 15; + phase = 0; + count = counts[0]; + } + else + { + phase = 1; + count = counts[1]; + } + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + static void + pfr_bitwriter_decode_rle2( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( p >= limit ) + break; + + count = *p++; + phase = phase ^ 1; + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + left = writer->width; + + writer->line += writer->pitch; + cur = writer->line; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP DATA DECODING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + pfr_lookup_bitmap_data( FT_Byte* base, + FT_Byte* limit, + FT_UInt count, + FT_UInt* flags, + FT_UInt char_code, + FT_ULong* found_offset, + FT_ULong* found_size ) + { + FT_UInt min, max, mid, char_len; + FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); + FT_Byte* buff; + + + char_len = 4; + if ( two ) + char_len += 1; + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + if ( !( *flags & PFR_BITMAP_CHARCODES_VALIDATED ) ) + { + FT_Byte* p; + FT_Byte* lim; + FT_UInt code; + FT_Long prev_code; + + + *flags |= PFR_BITMAP_VALID_CHARCODES; + prev_code = -1; + lim = base + count * char_len; + + if ( lim > limit ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " number of bitmap records too large,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + } + else + { + /* check whether records are sorted by code */ + for ( p = base; p < lim; p += char_len ) + { + if ( two ) + code = FT_PEEK_USHORT( p ); + else + code = *p; + + if ( (FT_Long)code <= prev_code ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " bitmap records are not sorted,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + break; + } + + prev_code = code; + } + } + + *flags |= PFR_BITMAP_CHARCODES_VALIDATED; + } + + /* ignore bitmaps in case table is not valid */ + /* (this might be sanitized, but PFR is dead...) */ + if ( !( *flags & PFR_BITMAP_VALID_CHARCODES ) ) + goto Fail; + + min = 0; + max = count; + mid = min + ( max - min ) / 2; + + /* binary search */ + while ( min < max ) + { + FT_UInt code; + + + buff = base + mid * char_len; + + if ( two ) + code = PFR_NEXT_USHORT( buff ); + else + code = PFR_NEXT_BYTE( buff ); + + if ( char_code < code ) + max = mid; + else if ( char_code > code ) + min = mid + 1; + else + goto Found_It; + + /* reasonable prediction in a continuous block */ + mid += char_code - code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + Fail: + /* Not found */ + *found_size = 0; + *found_offset = 0; + return; + + Found_It: + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + *found_size = PFR_NEXT_USHORT( buff ); + else + *found_size = PFR_NEXT_BYTE( buff ); + + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + *found_offset = PFR_NEXT_ULONG( buff ); + else + *found_offset = PFR_NEXT_USHORT( buff ); + } + + + /* load bitmap metrics. `*aadvance' must be set to the default value */ + /* before calling this function */ + /* */ + static FT_Error + pfr_load_bitmap_metrics( FT_Byte** pdata, + FT_Byte* limit, + FT_Long scaled_advance, + FT_Long *axpos, + FT_Long *aypos, + FT_UInt *axsize, + FT_UInt *aysize, + FT_Long *aadvance, + FT_UInt *aformat ) + { + FT_Error error = FT_Err_Ok; + FT_Byte flags; + FT_Byte b; + FT_Byte* p = *pdata; + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + xpos = 0; + ypos = 0; + xsize = 0; + ysize = 0; + advance = 0; + + switch ( flags & 3 ) + { + case 0: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xpos = (FT_Char)b >> 4; + ypos = ( (FT_Char)( b << 4 ) ) >> 4; + break; + + case 1: + PFR_CHECK( 2 ); + xpos = PFR_NEXT_INT8( p ); + ypos = PFR_NEXT_INT8( p ); + break; + + case 2: + PFR_CHECK( 4 ); + xpos = PFR_NEXT_SHORT( p ); + ypos = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 6 ); + xpos = PFR_NEXT_LONG( p ); + ypos = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + /* blank image */ + xsize = 0; + ysize = 0; + break; + + case 1: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xsize = ( b >> 4 ) & 0xF; + ysize = b & 0xF; + break; + + case 2: + PFR_CHECK( 2 ); + xsize = PFR_NEXT_BYTE( p ); + ysize = PFR_NEXT_BYTE( p ); + break; + + case 3: + PFR_CHECK( 4 ); + xsize = PFR_NEXT_USHORT( p ); + ysize = PFR_NEXT_USHORT( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + advance = scaled_advance; + break; + + case 1: + PFR_CHECK( 1 ); + advance = PFR_NEXT_INT8( p ) * 256; + break; + + case 2: + PFR_CHECK( 2 ); + advance = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 3 ); + advance = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + *axpos = xpos; + *aypos = ypos; + *axsize = xsize; + *aysize = ysize; + *aadvance = advance; + *aformat = flags >> 2; + *pdata = p; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_load_bitmap_bits( FT_Byte* p, + FT_Byte* limit, + FT_UInt format, + FT_Bool decreasing, + FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + PFR_BitWriterRec writer; + + + if ( target->rows > 0 && target->width > 0 ) + { + pfr_bitwriter_init( &writer, target, decreasing ); + + switch ( format ) + { + case 0: /* packed bits */ + pfr_bitwriter_decode_bytes( &writer, p, limit ); + break; + + case 1: /* RLE1 */ + pfr_bitwriter_decode_rle1( &writer, p, limit ); + break; + + case 2: /* RLE2 */ + pfr_bitwriter_decode_rle2( &writer, p, limit ); + break; + + default: + ; + } + } + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP LOADING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ) + { + FT_Error error; + PFR_Face face = (PFR_Face) glyph->root.face; + FT_Stream stream = face->root.stream; + PFR_PhyFont phys = &face->phy_font; + FT_ULong gps_offset; + FT_ULong gps_size; + PFR_Char character; + PFR_Strike strike; + + + character = &phys->chars[glyph_index]; + + /* look up a bitmap strike corresponding to the current */ + /* character dimensions */ + { + FT_UInt n; + + + strike = phys->strikes; + for ( n = 0; n < phys->num_strikes; n++ ) + { + if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && + strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) + goto Found_Strike; + + strike++; + } + + /* couldn't find it */ + return FT_THROW( Invalid_Argument ); + } + + Found_Strike: + + /* now look up the glyph's position within the file */ + { + FT_UInt char_len; + + + char_len = 4; + if ( strike->flags & PFR_BITMAP_2BYTE_CHARCODE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + /* access data directly in the frame to speed up lookups */ + if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || + FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) + goto Exit; + + pfr_lookup_bitmap_data( stream->cursor, + stream->limit, + strike->num_bitmaps, + &strike->flags, + character->char_code, + &gps_offset, + &gps_size ); + + FT_FRAME_EXIT(); + + if ( gps_size == 0 ) + { + /* could not find a bitmap program string for this glyph */ + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + /* get the bitmap metrics */ + { + FT_Long xpos = 0, ypos = 0, advance = 0; + FT_UInt xsize = 0, ysize = 0, format = 0; + FT_Byte* p; + + + /* compute linear advance */ + advance = character->advance; + if ( phys->metrics_resolution != phys->outline_resolution ) + advance = FT_MulDiv( advance, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + glyph->root.linearHoriAdvance = advance; + + /* compute default advance, i.e., scaled advance; this can be */ + /* overridden in the bitmap header of certain glyphs */ + advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, + character->advance, + (FT_Long)phys->metrics_resolution ); + + if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || + FT_FRAME_ENTER( gps_size ) ) + goto Exit; + + p = stream->cursor; + error = pfr_load_bitmap_metrics( &p, stream->limit, + advance, + &xpos, &ypos, + &xsize, &ysize, + &advance, &format ); + if ( error ) + goto Exit1; + + /* + * Before allocating the target bitmap, we check whether the given + * bitmap dimensions are valid, depending on the image format. + * + * Format 0: We have a stream of pixels (with 8 pixels per byte). + * + * (xsize * ysize + 7) / 8 <= gps_size + * + * Format 1: Run-length encoding; the high nibble holds the number of + * white bits, the low nibble the number of black bits. In + * other words, a single byte can represent at most 15 + * pixels. + * + * xsize * ysize <= 15 * gps_size + * + * Format 2: Run-length encoding; the high byte holds the number of + * white bits, the low byte the number of black bits. In + * other words, two bytes can represent at most 255 pixels. + * + * xsize * ysize <= 255 * (gps_size + 1) / 2 + */ + switch ( format ) + { + case 0: + if ( ( (FT_ULong)xsize * ysize + 7 ) / 8 > gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 1: + if ( (FT_ULong)xsize * ysize > 15 * gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 2: + if ( (FT_ULong)xsize * ysize > 255 * ( ( gps_size + 1 ) / 2 ) ) + error = FT_THROW( Invalid_Table ); + break; + default: + FT_ERROR(( "pfr_slot_load_bitmap: invalid image type\n" )); + error = FT_THROW( Invalid_Table ); + } + + if ( error ) + { + if ( FT_ERR_EQ( error, Invalid_Table ) ) + FT_ERROR(( "pfr_slot_load_bitmap: invalid bitmap dimensions\n" )); + goto Exit1; + } + + /* + * XXX: on 16bit systems we return an error for huge bitmaps + * that cause size truncation, because truncated + * size properties make bitmap glyphs broken. + */ + if ( xpos > FT_INT_MAX || + xpos < FT_INT_MIN || + ysize > FT_INT_MAX || + ypos > FT_INT_MAX - (FT_Long)ysize || + ypos + (FT_Long)ysize < FT_INT_MIN ) + { + FT_TRACE1(( "pfr_slot_load_bitmap:" + " huge bitmap glyph %ldx%ld over FT_GlyphSlot\n", + xpos, ypos )); + error = FT_THROW( Invalid_Pixel_Size ); + } + + if ( !error ) + { + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + /* Set up glyph bitmap and metrics */ + + /* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */ + glyph->root.bitmap.width = xsize; + glyph->root.bitmap.rows = ysize; + glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3; + glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + /* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */ + glyph->root.metrics.width = (FT_Pos)xsize << 6; + glyph->root.metrics.height = (FT_Pos)ysize << 6; + glyph->root.metrics.horiBearingX = xpos * 64; + glyph->root.metrics.horiBearingY = ypos * 64; + glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); + glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; + glyph->root.metrics.vertBearingY = 0; + glyph->root.metrics.vertAdvance = size->root.metrics.height; + + /* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */ + glyph->root.bitmap_left = (FT_Int)xpos; + glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize ); + + if ( metrics_only ) + goto Exit1; + + /* Allocate and read bitmap data */ + { + FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize; + + + error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); + if ( !error ) + error = pfr_load_bitmap_bits( + p, + stream->limit, + format, + FT_BOOL( face->header.color_flags & + PFR_FLAG_INVERT_BITMAP ), + &glyph->root.bitmap ); + } + } + + Exit1: + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrsbit.h b/modules/freetype2/src/pfr/pfrsbit.h new file mode 100644 index 0000000000..3e1dba9ae9 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrsbit.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * pfrsbit.h + * + * FreeType PFR bitmap loader (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 PFRSBIT_H_ +#define PFRSBIT_H_ + +#include "pfrobjs.h" + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ); + +FT_END_HEADER + +#endif /* PFRSBIT_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/pfrtypes.h b/modules/freetype2/src/pfr/pfrtypes.h new file mode 100644 index 0000000000..2f8909f062 --- /dev/null +++ b/modules/freetype2/src/pfr/pfrtypes.h @@ -0,0 +1,331 @@ +/**************************************************************************** + * + * pfrtypes.h + * + * FreeType PFR data structures (specification only). + * + * 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 PFRTYPES_H_ +#define PFRTYPES_H_ + +#include <freetype/internal/ftobjs.h> + +FT_BEGIN_HEADER + + /************************************************************************/ + + /* the PFR Header structure */ + typedef struct PFR_HeaderRec_ + { + FT_UInt32 signature; + FT_UInt version; + FT_UInt signature2; + FT_UInt header_size; + + FT_UInt log_dir_size; + FT_UInt log_dir_offset; + + FT_UInt log_font_max_size; + FT_UInt32 log_font_section_size; + FT_UInt32 log_font_section_offset; + + FT_UInt32 phy_font_max_size; + FT_UInt32 phy_font_section_size; + FT_UInt32 phy_font_section_offset; + + FT_UInt gps_max_size; + FT_UInt32 gps_section_size; + FT_UInt32 gps_section_offset; + + FT_UInt max_blue_values; + FT_UInt max_x_orus; + FT_UInt max_y_orus; + + FT_UInt phy_font_max_size_high; + FT_UInt color_flags; + + FT_UInt32 bct_max_size; + FT_UInt32 bct_set_max_size; + FT_UInt32 phy_bct_set_max_size; + + FT_UInt num_phy_fonts; + FT_UInt max_vert_stem_snap; + FT_UInt max_horz_stem_snap; + FT_UInt max_chars; + + } PFR_HeaderRec, *PFR_Header; + + + /* used in `color_flags' field of the PFR_Header */ +#define PFR_FLAG_BLACK_PIXEL 0x01U +#define PFR_FLAG_INVERT_BITMAP 0x02U + + + /************************************************************************/ + + typedef struct PFR_LogFontRec_ + { + FT_UInt32 size; + FT_UInt32 offset; + + FT_Int32 matrix[4]; + FT_UInt stroke_flags; + FT_Int stroke_thickness; + FT_Int bold_thickness; + FT_Int32 miter_limit; + + FT_UInt32 phys_size; + FT_UInt32 phys_offset; + + } PFR_LogFontRec, *PFR_LogFont; + + +#define PFR_LINE_JOIN_MITER 0x00U +#define PFR_LINE_JOIN_ROUND 0x01U +#define PFR_LINE_JOIN_BEVEL 0x02U +#define PFR_LINE_JOIN_MASK ( PFR_LINE_JOIN_ROUND | PFR_LINE_JOIN_BEVEL ) + +#define PFR_LOG_STROKE 0x04U +#define PFR_LOG_2BYTE_STROKE 0x08U +#define PFR_LOG_BOLD 0x10U +#define PFR_LOG_2BYTE_BOLD 0x20U +#define PFR_LOG_EXTRA_ITEMS 0x40U + + + /************************************************************************/ + +#define PFR_BITMAP_2BYTE_CHARCODE 0x01U +#define PFR_BITMAP_2BYTE_SIZE 0x02U +#define PFR_BITMAP_3BYTE_OFFSET 0x04U + + /* not part of the specification but used for implementation */ +#define PFR_BITMAP_CHARCODES_VALIDATED 0x40U +#define PFR_BITMAP_VALID_CHARCODES 0x80U + + + typedef struct PFR_BitmapCharRec_ + { + FT_UInt char_code; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_BitmapCharRec, *PFR_BitmapChar; + + +#define PFR_STRIKE_2BYTE_XPPM 0x01U +#define PFR_STRIKE_2BYTE_YPPM 0x02U +#define PFR_STRIKE_3BYTE_SIZE 0x04U +#define PFR_STRIKE_3BYTE_OFFSET 0x08U +#define PFR_STRIKE_2BYTE_COUNT 0x10U + + + typedef struct PFR_StrikeRec_ + { + FT_UInt x_ppm; + FT_UInt y_ppm; + FT_UInt flags; + + FT_UInt32 gps_size; + FT_UInt32 gps_offset; + + FT_UInt32 bct_size; + FT_UInt32 bct_offset; + + /* optional */ + FT_UInt num_bitmaps; + PFR_BitmapChar bitmaps; + + } PFR_StrikeRec, *PFR_Strike; + + + /************************************************************************/ + + typedef struct PFR_CharRec_ + { + FT_UInt char_code; + FT_Int advance; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_CharRec, *PFR_Char; + + + /************************************************************************/ + + typedef struct PFR_DimensionRec_ + { + FT_UInt standard; + FT_UInt num_stem_snaps; + FT_Int* stem_snaps; + + } PFR_DimensionRec, *PFR_Dimension; + + /************************************************************************/ + + typedef struct PFR_KernItemRec_* PFR_KernItem; + + typedef struct PFR_KernItemRec_ + { + PFR_KernItem next; + FT_Byte pair_count; + FT_Byte flags; + FT_Short base_adj; + FT_UInt pair_size; + FT_Offset offset; + FT_UInt32 pair1; + FT_UInt32 pair2; + + } PFR_KernItemRec; + + +#define PFR_KERN_INDEX( g1, g2 ) \ + ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) ) + +#define PFR_KERN_PAIR_INDEX( pair ) \ + PFR_KERN_INDEX( (pair)->glyph1, (pair)->glyph2 ) + +#define PFR_NEXT_KPAIR( p ) ( p += 2, \ + ( (FT_UInt32)p[-2] << 16 ) | p[-1] ) + + + /************************************************************************/ + + typedef struct PFR_PhyFontRec_ + { + FT_Memory memory; + FT_UInt32 offset; + + FT_UInt font_ref_number; + FT_UInt outline_resolution; + FT_UInt metrics_resolution; + FT_BBox bbox; + FT_UInt flags; + FT_Int standard_advance; + + FT_Int ascent; /* optional, bbox.yMax if not present */ + FT_Int descent; /* optional, bbox.yMin if not present */ + FT_Int leading; /* optional, 0 if not present */ + + PFR_DimensionRec horizontal; + PFR_DimensionRec vertical; + + FT_String* font_id; + FT_String* family_name; + FT_String* style_name; + + FT_UInt num_strikes; + FT_UInt max_strikes; + PFR_StrikeRec* strikes; + + FT_UInt num_blue_values; + FT_Int *blue_values; + FT_UInt blue_fuzz; + FT_UInt blue_scale; + + FT_UInt num_chars; + FT_Offset chars_offset; + PFR_Char chars; + + FT_UInt num_kern_pairs; + PFR_KernItem kern_items; + PFR_KernItem* kern_items_tail; + + /* not part of the spec, but used during load */ + FT_ULong bct_offset; + FT_Byte* cursor; + + } PFR_PhyFontRec, *PFR_PhyFont; + + +#define PFR_PHY_VERTICAL 0x01U +#define PFR_PHY_2BYTE_CHARCODE 0x02U +#define PFR_PHY_PROPORTIONAL 0x04U +#define PFR_PHY_ASCII_CODE 0x08U +#define PFR_PHY_2BYTE_GPS_SIZE 0x10U +#define PFR_PHY_3BYTE_GPS_OFFSET 0x20U +#define PFR_PHY_EXTRA_ITEMS 0x80U + + +#define PFR_KERN_2BYTE_CHAR 0x01U +#define PFR_KERN_2BYTE_ADJ 0x02U + + + /************************************************************************/ + +#define PFR_GLYPH_YCOUNT 0x01U +#define PFR_GLYPH_XCOUNT 0x02U +#define PFR_GLYPH_1BYTE_XYCOUNT 0x04U + +#define PFR_GLYPH_SINGLE_EXTRA_ITEMS 0x08U +#define PFR_GLYPH_COMPOUND_EXTRA_ITEMS 0x40U + +#define PFR_GLYPH_IS_COMPOUND 0x80U + + + /* controlled coordinate */ + typedef struct PFR_CoordRec_ + { + FT_UInt org; + FT_UInt cur; + + } PFR_CoordRec, *PFR_Coord; + + + typedef struct PFR_SubGlyphRec_ + { + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Int x_delta; + FT_Int y_delta; + FT_UInt32 gps_offset; + FT_UInt gps_size; + + } PFR_SubGlyphRec, *PFR_SubGlyph; + + +#define PFR_SUBGLYPH_XSCALE 0x10U +#define PFR_SUBGLYPH_YSCALE 0x20U +#define PFR_SUBGLYPH_2BYTE_SIZE 0x40U +#define PFR_SUBGLYPH_3BYTE_OFFSET 0x80U + + + typedef struct PFR_GlyphRec_ + { + FT_Byte format; + +#if 0 + FT_UInt num_x_control; + FT_UInt num_y_control; +#endif + FT_UInt max_xy_control; + FT_Pos* x_control; + FT_Pos* y_control; + + + FT_UInt num_subs; + FT_UInt max_subs; + PFR_SubGlyphRec* subs; + + FT_GlyphLoader loader; + FT_Bool path_begun; + + } PFR_GlyphRec, *PFR_Glyph; + + +FT_END_HEADER + +#endif /* PFRTYPES_H_ */ + + +/* END */ diff --git a/modules/freetype2/src/pfr/rules.mk b/modules/freetype2/src/pfr/rules.mk new file mode 100644 index 0000000000..50695fd288 --- /dev/null +++ b/modules/freetype2/src/pfr/rules.mk @@ -0,0 +1,76 @@ +# +# FreeType 2 PFR driver configuration rules +# + + +# 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. + + +# pfr driver directory +# +PFR_DIR := $(SRC_DIR)/pfr + + +# compilation flags for the driver +# +PFR_COMPILE := $(CC) $(ANSIFLAGS) \ + $I$(subst /,$(COMPILER_SEP),$(PFR_DIR)) \ + $(INCLUDE_FLAGS) \ + $(FT_CFLAGS) + + +# pfr driver sources (i.e., C files) +# +PFR_DRV_SRC := $(PFR_DIR)/pfrload.c \ + $(PFR_DIR)/pfrgload.c \ + $(PFR_DIR)/pfrcmap.c \ + $(PFR_DIR)/pfrdrivr.c \ + $(PFR_DIR)/pfrsbit.c \ + $(PFR_DIR)/pfrobjs.c + +# pfr driver headers +# +PFR_DRV_H := $(PFR_DRV_SRC:%.c=%.h) \ + $(PFR_DIR)/pfrerror.h \ + $(PFR_DIR)/pfrtypes.h + + +# Pfr driver object(s) +# +# PFR_DRV_OBJ_M is used during `multi' builds +# PFR_DRV_OBJ_S is used during `single' builds +# +PFR_DRV_OBJ_M := $(PFR_DRV_SRC:$(PFR_DIR)/%.c=$(OBJ_DIR)/%.$O) +PFR_DRV_OBJ_S := $(OBJ_DIR)/pfr.$O + +# pfr driver source file for single build +# +PFR_DRV_SRC_S := $(PFR_DIR)/pfr.c + + +# pfr driver - single object +# +$(PFR_DRV_OBJ_S): $(PFR_DRV_SRC_S) $(PFR_DRV_SRC) $(FREETYPE_H) $(PFR_DRV_H) + $(PFR_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PFR_DRV_SRC_S)) + + +# pfr driver - multiple objects +# +$(OBJ_DIR)/%.$O: $(PFR_DIR)/%.c $(FREETYPE_H) $(PFR_DRV_H) + $(PFR_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<) + + +# update main driver object lists +# +DRV_OBJS_S += $(PFR_DRV_OBJ_S) +DRV_OBJS_M += $(PFR_DRV_OBJ_M) + + +# EOF |