summaryrefslogtreecommitdiffstats
path: root/modules/freetype2/src/pfr
diff options
context:
space:
mode:
Diffstat (limited to 'modules/freetype2/src/pfr')
-rw-r--r--modules/freetype2/src/pfr/module.mk23
-rw-r--r--modules/freetype2/src/pfr/pfr.c29
-rw-r--r--modules/freetype2/src/pfr/pfrcmap.c182
-rw-r--r--modules/freetype2/src/pfr/pfrcmap.h45
-rw-r--r--modules/freetype2/src/pfr/pfrdrivr.c212
-rw-r--r--modules/freetype2/src/pfr/pfrdrivr.h36
-rw-r--r--modules/freetype2/src/pfr/pfrerror.h41
-rw-r--r--modules/freetype2/src/pfr/pfrgload.c850
-rw-r--r--modules/freetype2/src/pfr/pfrgload.h49
-rw-r--r--modules/freetype2/src/pfr/pfrload.c1058
-rw-r--r--modules/freetype2/src/pfr/pfrload.h123
-rw-r--r--modules/freetype2/src/pfr/pfrobjs.c603
-rw-r--r--modules/freetype2/src/pfr/pfrobjs.h96
-rw-r--r--modules/freetype2/src/pfr/pfrsbit.c813
-rw-r--r--modules/freetype2/src/pfr/pfrsbit.h37
-rw-r--r--modules/freetype2/src/pfr/pfrtypes.h331
-rw-r--r--modules/freetype2/src/pfr/rules.mk76
17 files changed, 4604 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..312a9ffe17
--- /dev/null
+++ b/modules/freetype2/src/pfr/pfrcmap.c
@@ -0,0 +1,182 @@
+/****************************************************************************
+ *
+ * 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( PFR_CMap cmap,
+ FT_Pointer pointer )
+ {
+ FT_Error error = FT_Err_Ok;
+ PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
+
+ FT_UNUSED( pointer );
+
+
+ cmap->num_chars = face->phy_font.num_chars;
+ cmap->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 < cmap->num_chars; n++ )
+ {
+ if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pfr_cmap_done( PFR_CMap cmap )
+ {
+ cmap->chars = NULL;
+ cmap->num_chars = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pfr_cmap_char_index( PFR_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_chars;
+ FT_UInt mid = min + ( max - min ) / 2;
+ PFR_Char gchar;
+
+
+ while ( min < max )
+ {
+ gchar = cmap->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_UInt32 )
+ pfr_cmap_char_next( PFR_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ Restart:
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_chars;
+ FT_UInt mid = min + ( max - min ) / 2;
+ PFR_Char gchar;
+
+
+ while ( min < max )
+ {
+ gchar = cmap->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 < cmap->num_chars )
+ {
+ gchar = cmap->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..78c6c6882c
--- /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 pfrface, /* PFR_Face */
+ FT_UInt left,
+ FT_UInt right,
+ FT_Vector *avector )
+ {
+ PFR_Face face = (PFR_Face)pfrface;
+ PFR_PhyFont phys = &face->phy_font;
+
+
+ (void)pfr_face_get_kerning( pfrface, 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 pfrface, /* PFR_Face */
+ FT_UInt gindex,
+ FT_Pos *anadvance )
+ {
+ PFR_Face face = (PFR_Face)pfrface;
+ FT_Error error = FT_ERR( Invalid_Argument );
+
+
+ *anadvance = 0;
+
+ if ( !gindex )
+ goto Exit;
+
+ gindex--;
+
+ if ( face )
+ {
+ PFR_PhyFont phys = &face->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 pfrface, /* PFR_Face */
+ FT_UInt *anoutline_resolution,
+ FT_UInt *ametrics_resolution,
+ FT_Fixed *ametrics_x_scale,
+ FT_Fixed *ametrics_y_scale )
+ {
+ PFR_Face face = (PFR_Face)pfrface;
+ PFR_PhyFont phys = &face->phy_font;
+ FT_Fixed x_scale, y_scale;
+ FT_Size size = face->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..14f2ec3778
--- /dev/null
+++ b/modules/freetype2/src/pfr/pfrgload.c
@@ -0,0 +1,850 @@
+/****************************************************************************
+ *
+ * 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_GlyphLoader loader = glyph->loader;
+ FT_Memory memory = 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..de85ee6aad
--- /dev/null
+++ b/modules/freetype2/src/pfr/pfrload.c
@@ -0,0 +1,1058 @@
+/****************************************************************************
+ *
+ * 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,
+ 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,
+ 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,
+ 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,
+ 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_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info },
+ { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id },
+ { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps },
+ { 4, (PFR_ExtraItem_ParseFunc)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..3db8f0a060
--- /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->driver->root.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, FT_FACE_MEMORY( face ) );
+
+ /* 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->stream->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