summaryrefslogtreecommitdiffstats
path: root/modules/freetype2/src/pcf
diff options
context:
space:
mode:
Diffstat (limited to 'modules/freetype2/src/pcf')
-rw-r--r--modules/freetype2/src/pcf/README96
-rw-r--r--modules/freetype2/src/pcf/module.mk34
-rw-r--r--modules/freetype2/src/pcf/pcf.c35
-rw-r--r--modules/freetype2/src/pcf/pcf.h251
-rw-r--r--modules/freetype2/src/pcf/pcfdrivr.c832
-rw-r--r--modules/freetype2/src/pcf/pcfdrivr.h44
-rw-r--r--modules/freetype2/src/pcf/pcferror.h41
-rw-r--r--modules/freetype2/src/pcf/pcfread.c1731
-rw-r--r--modules/freetype2/src/pcf/pcfread.h44
-rw-r--r--modules/freetype2/src/pcf/pcfutil.c119
-rw-r--r--modules/freetype2/src/pcf/pcfutil.h55
-rw-r--r--modules/freetype2/src/pcf/rules.mk82
12 files changed, 3364 insertions, 0 deletions
diff --git a/modules/freetype2/src/pcf/README b/modules/freetype2/src/pcf/README
new file mode 100644
index 0000000000..09ea970eda
--- /dev/null
+++ b/modules/freetype2/src/pcf/README
@@ -0,0 +1,96 @@
+ FreeType font driver for PCF fonts
+
+ Francesco Zappa Nardelli
+ <francesco.zappa.nardelli@ens.fr>
+
+
+Introduction
+************
+
+PCF (Portable Compiled Format) is a binary bitmap font format, largely used
+in X world. This code implements a PCF driver for the FreeType library.
+Glyph images are loaded into memory only on demand, thus leading to a small
+memory footprint.
+
+Information on the PCF font format can only be worked out from
+`pcfread.c', and `pcfwrite.c', to be found, for instance, in the XFree86
+(www.xfree86.org) source tree (xc/lib/font/bitmap/).
+
+Many good bitmap fonts in bdf format come with XFree86: they can be
+compiled into the pcf format using the `bdftopcf' utility.
+
+
+Supported hardware
+******************
+
+The driver has been tested on linux/x86 and sunos5.5/sparc. In both
+cases the compiler was gcc. When back in Paris, I will test it also
+on linux/alpha.
+
+
+Encodings
+*********
+
+Use `FT_Get_BDF_Charset_ID' to access the encoding and registry.
+
+The driver always exports `ft_encoding_none' as face->charmap.encoding.
+FT_Get_Char_Index() behavior is unmodified, that is, it converts the ULong
+value given as argument into the corresponding glyph number.
+
+
+Known problems
+**************
+
+- dealing explicitly with encodings breaks the uniformity of FreeType 2
+ API.
+
+- except for encodings properties, client applications have no
+ visibility of the PCF_Face object. This means that applications
+ cannot directly access font tables and are obliged to trust
+ FreeType.
+
+- currently, glyph names and ink_metrics are ignored.
+
+I plan to give full visibility of the PCF_Face object in the next
+release of the driver, thus implementing also glyph names and
+ink_metrics.
+
+- height is defined as (ascent - descent). Is this correct?
+
+- if unable to read size information from the font, PCF_Init_Face
+ sets available_size->width and available_size->height to 12.
+
+- too many english grammar errors in the readme file :-(
+
+
+License
+*******
+
+Copyright (C) 2000 by Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+Credits
+*******
+
+Keith Packard wrote the pcf driver found in XFree86. His work is at
+the same time the specification and the sample implementation of the
+PCF format. Undoubtedly, this driver is inspired from his work.
diff --git a/modules/freetype2/src/pcf/module.mk b/modules/freetype2/src/pcf/module.mk
new file mode 100644
index 0000000000..df383ff0fb
--- /dev/null
+++ b/modules/freetype2/src/pcf/module.mk
@@ -0,0 +1,34 @@
+#
+# FreeType 2 PCF module definition
+#
+
+# Copyright 2000, 2006 by
+# Francesco Zappa Nardelli
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+FTMODULE_H_COMMANDS += PCF_DRIVER
+
+define PCF_DRIVER
+$(OPEN_DRIVER) FT_Driver_ClassRec, pcf_driver_class $(CLOSE_DRIVER)
+$(ECHO_DRIVER)pcf $(ECHO_DRIVER_DESC)pcf bitmap fonts$(ECHO_DRIVER_DONE)
+endef
+
+# EOF
diff --git a/modules/freetype2/src/pcf/pcf.c b/modules/freetype2/src/pcf/pcf.c
new file mode 100644
index 0000000000..6b30fb249a
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcf.c
@@ -0,0 +1,35 @@
+/* pcf.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001, 2003 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "pcfdrivr.c"
+#include "pcfread.c"
+#include "pcfutil.c"
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcf.h b/modules/freetype2/src/pcf/pcf.h
new file mode 100644
index 0000000000..3134cc355b
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcf.h
@@ -0,0 +1,251 @@
+/* pcf.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright (C) 2000, 2001, 2002, 2003, 2006, 2010 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef PCF_H_
+#define PCF_H_
+
+
+#include <freetype/internal/ftdrv.h>
+#include <freetype/internal/ftstream.h>
+
+
+FT_BEGIN_HEADER
+
+ typedef struct PCF_TableRec_
+ {
+ FT_ULong type;
+ FT_ULong format;
+ FT_ULong size;
+ FT_ULong offset;
+
+ } PCF_TableRec, *PCF_Table;
+
+
+ typedef struct PCF_TocRec_
+ {
+ FT_ULong version;
+ FT_ULong count;
+ PCF_Table tables;
+
+ } PCF_TocRec, *PCF_Toc;
+
+
+ typedef struct PCF_ParsePropertyRec_
+ {
+ FT_Long name;
+ FT_Byte isString;
+ FT_Long value;
+
+ } PCF_ParsePropertyRec, *PCF_ParseProperty;
+
+
+ typedef struct PCF_PropertyRec_
+ {
+ FT_String* name;
+ FT_Byte isString;
+
+ union
+ {
+ FT_String* atom;
+ FT_Long l;
+ FT_ULong ul;
+
+ } value;
+
+ } PCF_PropertyRec, *PCF_Property;
+
+
+ typedef struct PCF_Compressed_MetricRec_
+ {
+ FT_Byte leftSideBearing;
+ FT_Byte rightSideBearing;
+ FT_Byte characterWidth;
+ FT_Byte ascent;
+ FT_Byte descent;
+
+ } PCF_Compressed_MetricRec, *PCF_Compressed_Metric;
+
+
+ typedef struct PCF_MetricRec_
+ {
+ FT_Short leftSideBearing;
+ FT_Short rightSideBearing;
+ FT_Short characterWidth;
+ FT_Short ascent;
+ FT_Short descent;
+ FT_Short attributes;
+
+ FT_ULong bits; /* offset into the PCF_BITMAPS table */
+
+ } PCF_MetricRec, *PCF_Metric;
+
+
+ typedef struct PCF_EncRec_
+ {
+ FT_UShort firstCol;
+ FT_UShort lastCol;
+ FT_UShort firstRow;
+ FT_UShort lastRow;
+ FT_UShort defaultChar;
+
+ FT_UShort* offset;
+
+ } PCF_EncRec, *PCF_Enc;
+
+
+ typedef struct PCF_AccelRec_
+ {
+ FT_Byte noOverlap;
+ FT_Byte constantMetrics;
+ FT_Byte terminalFont;
+ FT_Byte constantWidth;
+ FT_Byte inkInside;
+ FT_Byte inkMetrics;
+ FT_Byte drawDirection;
+ FT_Long fontAscent;
+ FT_Long fontDescent;
+ FT_Long maxOverlap;
+ PCF_MetricRec minbounds;
+ PCF_MetricRec maxbounds;
+ PCF_MetricRec ink_minbounds;
+ PCF_MetricRec ink_maxbounds;
+
+ } PCF_AccelRec, *PCF_Accel;
+
+
+ /*
+ * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
+ * is the same as a `character code' in FreeType speak.
+ */
+ typedef struct PCF_FaceRec_
+ {
+ FT_FaceRec root;
+
+ FT_StreamRec comp_stream;
+ FT_Stream comp_source;
+
+ char* charset_encoding;
+ char* charset_registry;
+
+ PCF_TocRec toc;
+ PCF_AccelRec accel;
+
+ int nprops;
+ PCF_Property properties;
+
+ FT_ULong nmetrics;
+ PCF_Metric metrics;
+
+ PCF_EncRec enc;
+
+ FT_ULong bitmapsFormat;
+
+ } PCF_FaceRec, *PCF_Face;
+
+
+ typedef struct PCF_DriverRec_
+ {
+ FT_DriverRec root;
+
+ FT_Bool no_long_family_names;
+
+ } PCF_DriverRec, *PCF_Driver;
+
+
+ /* macros for pcf font format */
+
+#define LSBFirst 0
+#define MSBFirst 1
+
+#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \
+ ( 'c' << 16 ) | \
+ ( 'f' << 8 ) | 1 )
+#define PCF_FORMAT_MASK 0xFFFFFF00UL
+
+#define PCF_DEFAULT_FORMAT 0x00000000UL
+#define PCF_INKBOUNDS 0x00000200UL
+#define PCF_ACCEL_W_INKBOUNDS 0x00000100UL
+#define PCF_COMPRESSED_METRICS 0x00000100UL
+
+#define PCF_FORMAT_MATCH( a, b ) \
+ ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) )
+
+#define PCF_GLYPH_PAD_MASK ( 3 << 0 )
+#define PCF_BYTE_MASK ( 1 << 2 )
+#define PCF_BIT_MASK ( 1 << 3 )
+#define PCF_SCAN_UNIT_MASK ( 3 << 4 )
+
+#define PCF_BYTE_ORDER( f ) \
+ ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_BIT_ORDER( f ) \
+ ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_GLYPH_PAD_INDEX( f ) \
+ ( (f) & PCF_GLYPH_PAD_MASK )
+#define PCF_GLYPH_PAD( f ) \
+ ( 1 << PCF_GLYPH_PAD_INDEX( f ) )
+#define PCF_SCAN_UNIT_INDEX( f ) \
+ ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 )
+#define PCF_SCAN_UNIT( f ) \
+ ( 1 << PCF_SCAN_UNIT_INDEX( f ) )
+#define PCF_FORMAT_BITS( f ) \
+ ( (f) & ( PCF_GLYPH_PAD_MASK | \
+ PCF_BYTE_MASK | \
+ PCF_BIT_MASK | \
+ PCF_SCAN_UNIT_MASK ) )
+
+#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 )
+#define PCF_INDEX_TO_SIZE( b ) ( 1 << b )
+
+#define PCF_FORMAT( bit, byte, glyph, scan ) \
+ ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \
+ ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \
+ ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \
+ ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) )
+
+#define PCF_PROPERTIES ( 1 << 0 )
+#define PCF_ACCELERATORS ( 1 << 1 )
+#define PCF_METRICS ( 1 << 2 )
+#define PCF_BITMAPS ( 1 << 3 )
+#define PCF_INK_METRICS ( 1 << 4 )
+#define PCF_BDF_ENCODINGS ( 1 << 5 )
+#define PCF_SWIDTHS ( 1 << 6 )
+#define PCF_GLYPH_NAMES ( 1 << 7 )
+#define PCF_BDF_ACCELERATORS ( 1 << 8 )
+
+#define GLYPHPADOPTIONS 4 /* I'm not sure about this */
+
+ FT_LOCAL( FT_Error )
+ pcf_load_font( FT_Stream stream,
+ PCF_Face face,
+ FT_Long face_index );
+
+FT_END_HEADER
+
+#endif /* PCF_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfdrivr.c b/modules/freetype2/src/pcf/pcfdrivr.c
new file mode 100644
index 0000000000..bfa6eacca4
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfdrivr.c
@@ -0,0 +1,832 @@
+/* pcfdrivr.c
+
+ FreeType font driver for pcf files
+
+ Copyright (C) 2000-2004, 2006-2011, 2013, 2014 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/ftgzip.h>
+#include <freetype/ftlzw.h>
+#include <freetype/ftbzip2.h>
+#include <freetype/fterrors.h>
+#include <freetype/ftbdf.h>
+#include <freetype/ttnameid.h>
+
+#include "pcf.h"
+#include "pcfdrivr.h"
+#include "pcfread.h"
+
+#include "pcferror.h"
+#include "pcfutil.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT pcfread
+
+#include <freetype/internal/services/svbdf.h>
+#include <freetype/internal/services/svfntfmt.h>
+#include <freetype/internal/services/svprop.h>
+#include <freetype/ftdriver.h>
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT pcfdriver
+
+
+ /*
+ * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
+ * is the same as a `character code' in FreeType speak.
+ */
+ typedef struct PCF_CMapRec_
+ {
+ FT_CMapRec root;
+ PCF_Enc enc;
+
+ } PCF_CMapRec, *PCF_CMap;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_cmap_init( FT_CMap pcfcmap, /* PCF_CMap */
+ FT_Pointer init_data )
+ {
+ PCF_CMap cmap = (PCF_CMap)pcfcmap;
+ PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
+
+ FT_UNUSED( init_data );
+
+
+ cmap->enc = &face->enc;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pcf_cmap_done( FT_CMap pcfcmap ) /* PCF_CMap */
+ {
+ PCF_CMap cmap = (PCF_CMap)pcfcmap;
+
+
+ cmap->enc = NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_index( FT_CMap pcfcmap, /* PCF_CMap */
+ FT_UInt32 charcode )
+ {
+ PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+
+ FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
+ FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
+ FT_UInt32 h = enc->lastRow - enc->firstRow + 1;
+ FT_UInt32 w = enc->lastCol - enc->firstCol + 1;
+
+
+ /* wrapped around "negative" values are also rejected */
+ if ( i >= h || j >= w )
+ return 0;
+
+ return (FT_UInt)enc->offset[i * w + j];
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_next( FT_CMap pcfcmap, /* PCF_CMap */
+ FT_UInt32 *acharcode )
+ {
+ PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+ FT_UInt32 charcode = *acharcode + 1;
+
+ FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
+ FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
+ FT_UInt32 h = enc->lastRow - enc->firstRow + 1;
+ FT_UInt32 w = enc->lastCol - enc->firstCol + 1;
+
+ FT_UInt result = 0;
+
+
+ /* adjust wrapped around "negative" values */
+ if ( (FT_Int32)i < 0 )
+ i = 0;
+ if ( (FT_Int32)j < 0 )
+ j = 0;
+
+ for ( ; i < h; i++, j = 0 )
+ for ( ; j < w; j++ )
+ {
+ result = (FT_UInt)enc->offset[i * w + j];
+ if ( result != 0xFFFFU )
+ goto Exit;
+ }
+
+ Exit:
+ *acharcode = ( ( i + enc->firstRow ) << 8 ) | ( j + enc->firstCol );
+
+ return result;
+ }
+
+
+ static
+ const FT_CMap_ClassRec pcf_cmap_class =
+ {
+ sizeof ( PCF_CMapRec ),
+ pcf_cmap_init,
+ pcf_cmap_done,
+ pcf_cmap_char_index,
+ pcf_cmap_char_next,
+
+ NULL, NULL, NULL, NULL, NULL
+ };
+
+
+ FT_CALLBACK_DEF( void )
+ PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */
+ {
+ PCF_Face face = (PCF_Face)pcfface;
+ FT_Memory memory;
+
+
+ if ( !face )
+ return;
+
+ memory = FT_FACE_MEMORY( face );
+
+ FT_FREE( face->metrics );
+ FT_FREE( face->enc.offset );
+
+ /* free properties */
+ if ( face->properties )
+ {
+ FT_Int i;
+
+
+ for ( i = 0; i < face->nprops; i++ )
+ {
+ PCF_Property prop = &face->properties[i];
+
+
+ if ( prop )
+ {
+ FT_FREE( prop->name );
+ if ( prop->isString )
+ FT_FREE( prop->value.atom );
+ }
+ }
+
+ FT_FREE( face->properties );
+ }
+
+ FT_FREE( face->toc.tables );
+ FT_FREE( pcfface->family_name );
+ FT_FREE( pcfface->style_name );
+ FT_FREE( pcfface->available_sizes );
+ FT_FREE( face->charset_encoding );
+ FT_FREE( face->charset_registry );
+
+ /* close compressed stream if any */
+ if ( pcfface->stream == &face->comp_stream )
+ {
+ FT_Stream_Close( &face->comp_stream );
+ pcfface->stream = face->comp_source;
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Face_Init( FT_Stream stream,
+ FT_Face pcfface, /* PCF_Face */
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ PCF_Face face = (PCF_Face)pcfface;
+ FT_Error error;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ FT_TRACE2(( "PCF driver\n" ));
+
+ error = pcf_load_font( stream, face, face_index );
+ if ( error )
+ {
+ PCF_Face_Done( pcfface );
+
+#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \
+ defined( FT_CONFIG_OPTION_USE_LZW ) || \
+ defined( FT_CONFIG_OPTION_USE_BZIP2 )
+
+#ifdef FT_CONFIG_OPTION_USE_ZLIB
+ {
+ FT_Error error2;
+
+
+ /* this didn't work, try gzip support! */
+ FT_TRACE2(( " ... try gzip stream\n" ));
+ error2 = FT_Stream_OpenGzip( &face->comp_stream, stream );
+ if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
+ goto Fail;
+
+ error = error2;
+ }
+#endif /* FT_CONFIG_OPTION_USE_ZLIB */
+
+#ifdef FT_CONFIG_OPTION_USE_LZW
+ if ( error )
+ {
+ FT_Error error3;
+
+
+ /* this didn't work, try LZW support! */
+ FT_TRACE2(( " ... try LZW stream\n" ));
+ error3 = FT_Stream_OpenLZW( &face->comp_stream, stream );
+ if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
+ goto Fail;
+
+ error = error3;
+ }
+#endif /* FT_CONFIG_OPTION_USE_LZW */
+
+#ifdef FT_CONFIG_OPTION_USE_BZIP2
+ if ( error )
+ {
+ FT_Error error4;
+
+
+ /* this didn't work, try Bzip2 support! */
+ FT_TRACE2(( " ... try Bzip2 stream\n" ));
+ error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream );
+ if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
+ goto Fail;
+
+ error = error4;
+ }
+#endif /* FT_CONFIG_OPTION_USE_BZIP2 */
+
+ if ( error )
+ goto Fail;
+
+ face->comp_source = stream;
+ pcfface->stream = &face->comp_stream;
+
+ stream = pcfface->stream;
+
+ error = pcf_load_font( stream, face, face_index );
+ if ( error )
+ goto Fail;
+
+#else /* !(FT_CONFIG_OPTION_USE_ZLIB ||
+ FT_CONFIG_OPTION_USE_LZW ||
+ FT_CONFIG_OPTION_USE_BZIP2) */
+
+ goto Fail;
+
+#endif
+ }
+
+ /* PCF cannot have multiple faces in a single font file.
+ * XXX: A non-zero face_index is already an invalid argument, but
+ * Type1, Type42 drivers have a convention to return
+ * an invalid argument error when the font could be
+ * opened by the specified driver.
+ */
+ if ( face_index < 0 )
+ goto Exit;
+ else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
+ {
+ FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
+ PCF_Face_Done( pcfface );
+ return FT_THROW( Invalid_Argument );
+ }
+
+ /* set up charmap */
+ {
+ FT_String *charset_registry = face->charset_registry;
+ FT_String *charset_encoding = face->charset_encoding;
+ FT_Bool unicode_charmap = 0;
+
+
+ if ( charset_registry && charset_encoding )
+ {
+ char* s = charset_registry;
+
+
+ /* Uh, oh, compare first letters manually to avoid dependency
+ on locales. */
+ if ( ( s[0] == 'i' || s[0] == 'I' ) &&
+ ( s[1] == 's' || s[1] == 'S' ) &&
+ ( s[2] == 'o' || s[2] == 'O' ) )
+ {
+ s += 3;
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( face->charset_encoding, "1" ) ) )
+ unicode_charmap = 1;
+ /* another name for ASCII */
+ else if ( !ft_strcmp( s, "646.1991" ) &&
+ !ft_strcmp( face->charset_encoding, "IRV" ) )
+ unicode_charmap = 1;
+ }
+ }
+
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE;
+ /* initial platform/encoding should indicate unset status? */
+ charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
+ charmap.encoding_id = TT_APPLE_ID_DEFAULT;
+
+ if ( unicode_charmap )
+ {
+ charmap.encoding = FT_ENCODING_UNICODE;
+ charmap.platform_id = TT_PLATFORM_MICROSOFT;
+ charmap.encoding_id = TT_MS_ID_UNICODE_CS;
+ }
+
+ error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
+ }
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ FT_TRACE2(( " not a PCF file\n" ));
+ PCF_Face_Done( pcfface );
+ error = FT_THROW( Unknown_File_Format ); /* error */
+ goto Exit;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Size_Select( FT_Size size,
+ FT_ULong strike_index )
+ {
+ PCF_Accel accel = &( (PCF_Face)size->face )->accel;
+
+
+ FT_Select_Metrics( size->face, strike_index );
+
+ size->metrics.ascender = accel->fontAscent * 64;
+ size->metrics.descender = -accel->fontDescent * 64;
+ size->metrics.max_advance = accel->maxbounds.characterWidth * 64;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Size_Request( FT_Size size,
+ FT_Size_Request req )
+ {
+ PCF_Face face = (PCF_Face)size->face;
+ FT_Bitmap_Size* bsize = size->face->available_sizes;
+ FT_Error error = FT_ERR( Invalid_Pixel_Size );
+ FT_Long height;
+
+
+ height = FT_REQUEST_HEIGHT( req );
+ height = ( height + 32 ) >> 6;
+
+ switch ( req->type )
+ {
+ case FT_SIZE_REQUEST_TYPE_NOMINAL:
+ if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
+ error = FT_Err_Ok;
+ break;
+
+ case FT_SIZE_REQUEST_TYPE_REAL_DIM:
+ if ( height == ( face->accel.fontAscent +
+ face->accel.fontDescent ) )
+ error = FT_Err_Ok;
+ break;
+
+ default:
+ error = FT_THROW( Unimplemented_Feature );
+ break;
+ }
+
+ if ( error )
+ return error;
+ else
+ return PCF_Size_Select( size, 0 );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Glyph_Load( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+ FT_Stream stream;
+ FT_Error error = FT_Err_Ok;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ PCF_Metric metric;
+ FT_ULong bytes;
+
+
+ FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index ));
+
+ if ( !face )
+ {
+ error = FT_THROW( Invalid_Face_Handle );
+ goto Exit;
+ }
+
+ if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ stream = face->root.stream;
+
+ metric = face->metrics + glyph_index;
+
+ bitmap->rows = (unsigned int)( metric->ascent +
+ metric->descent );
+ bitmap->width = (unsigned int)( metric->rightSideBearing -
+ metric->leftSideBearing );
+ bitmap->num_grays = 1;
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+ switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
+ {
+ case 1:
+ bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 );
+ break;
+
+ case 2:
+ bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 );
+ break;
+
+ case 4:
+ bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 );
+ break;
+
+ case 8:
+ bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 );
+ break;
+
+ default:
+ return FT_THROW( Invalid_File_Format );
+ }
+
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+ slot->bitmap_left = metric->leftSideBearing;
+ slot->bitmap_top = metric->ascent;
+
+ slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 );
+ slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
+ slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
+ slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing -
+ metric->leftSideBearing ) * 64 );
+ slot->metrics.height = (FT_Pos)( bitmap->rows * 64 );
+
+ ft_synthesize_vertical_metrics( &slot->metrics,
+ ( face->accel.fontAscent +
+ face->accel.fontDescent ) * 64 );
+
+ if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
+ goto Exit;
+
+ /* XXX: to do: are there cases that need repadding the bitmap? */
+ bytes = (FT_ULong)bitmap->pitch * bitmap->rows;
+
+ error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes );
+ if ( error )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( metric->bits ) ||
+ FT_STREAM_READ( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
+ BitOrderInvert( bitmap->buffer, bytes );
+
+ if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
+ PCF_BIT_ORDER( face->bitmapsFormat ) ) )
+ {
+ switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
+ {
+ case 1:
+ break;
+
+ case 2:
+ TwoByteSwap( bitmap->buffer, bytes );
+ break;
+
+ case 4:
+ FourByteSwap( bitmap->buffer, bytes );
+ break;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*
+ *
+ * BDF SERVICE
+ *
+ */
+
+ static FT_Error
+ pcf_get_bdf_property( PCF_Face face,
+ const char* prop_name,
+ BDF_PropertyRec *aproperty )
+ {
+ PCF_Property prop;
+
+
+ prop = pcf_find_property( face, prop_name );
+ if ( prop )
+ {
+ if ( prop->isString )
+ {
+ aproperty->type = BDF_PROPERTY_TYPE_ATOM;
+ aproperty->u.atom = prop->value.atom;
+ }
+ else
+ {
+ if ( prop->value.l > 0x7FFFFFFFL ||
+ prop->value.l < ( -1 - 0x7FFFFFFFL ) )
+ {
+ FT_TRACE2(( "pcf_get_bdf_property:"
+ " too large integer 0x%lx is truncated\n",
+ prop->value.l ));
+ }
+
+ /*
+ * The PCF driver loads all properties as signed integers.
+ * This really doesn't seem to be a problem, because this is
+ * sufficient for any meaningful values.
+ */
+ aproperty->type = BDF_PROPERTY_TYPE_INTEGER;
+ aproperty->u.integer = (FT_Int32)prop->value.l;
+ }
+
+ return FT_Err_Ok;
+ }
+
+ return FT_THROW( Invalid_Argument );
+ }
+
+
+ static FT_Error
+ pcf_get_charset_id( PCF_Face face,
+ const char* *acharset_encoding,
+ const char* *acharset_registry )
+ {
+ *acharset_encoding = face->charset_encoding;
+ *acharset_registry = face->charset_registry;
+
+ return FT_Err_Ok;
+ }
+
+
+ static const FT_Service_BDFRec pcf_service_bdf =
+ {
+ (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, /* get_charset_id */
+ (FT_BDF_GetPropertyFunc) pcf_get_bdf_property /* get_property */
+ };
+
+
+ /*
+ * PROPERTY SERVICE
+ *
+ */
+ static FT_Error
+ pcf_property_set( FT_Module module, /* PCF_Driver */
+ const char* property_name,
+ const void* value,
+ FT_Bool value_is_string )
+ {
+#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
+
+ FT_Error error = FT_Err_Ok;
+ PCF_Driver driver = (PCF_Driver)module;
+
+#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
+ FT_UNUSED( value_is_string );
+#endif
+
+
+ if ( !ft_strcmp( property_name, "no-long-family-names" ) )
+ {
+#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
+ if ( value_is_string )
+ {
+ const char* s = (const char*)value;
+ long lfn = ft_strtol( s, NULL, 10 );
+
+
+ if ( lfn == 0 )
+ driver->no_long_family_names = 0;
+ else if ( lfn == 1 )
+ driver->no_long_family_names = 1;
+ else
+ return FT_THROW( Invalid_Argument );
+ }
+ else
+#endif
+ {
+ FT_Bool* no_long_family_names = (FT_Bool*)value;
+
+
+ driver->no_long_family_names = *no_long_family_names;
+ }
+
+ return error;
+ }
+
+#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+
+ FT_UNUSED( module );
+ FT_UNUSED( value );
+ FT_UNUSED( value_is_string );
+#ifndef FT_DEBUG_LEVEL_TRACE
+ FT_UNUSED( property_name );
+#endif
+
+#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+
+ FT_TRACE2(( "pcf_property_set: missing property `%s'\n",
+ property_name ));
+ return FT_THROW( Missing_Property );
+ }
+
+
+ static FT_Error
+ pcf_property_get( FT_Module module, /* PCF_Driver */
+ const char* property_name,
+ const void* value )
+ {
+#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
+
+ FT_Error error = FT_Err_Ok;
+ PCF_Driver driver = (PCF_Driver)module;
+
+
+ if ( !ft_strcmp( property_name, "no-long-family-names" ) )
+ {
+ FT_Bool no_long_family_names = driver->no_long_family_names;
+ FT_Bool* val = (FT_Bool*)value;
+
+
+ *val = no_long_family_names;
+
+ return error;
+ }
+
+#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+
+ FT_UNUSED( module );
+ FT_UNUSED( value );
+#ifndef FT_DEBUG_LEVEL_TRACE
+ FT_UNUSED( property_name );
+#endif
+
+#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+
+ FT_TRACE2(( "pcf_property_get: missing property `%s'\n",
+ property_name ));
+ return FT_THROW( Missing_Property );
+ }
+
+
+ FT_DEFINE_SERVICE_PROPERTIESREC(
+ pcf_service_properties,
+
+ (FT_Properties_SetFunc)pcf_property_set, /* set_property */
+ (FT_Properties_GetFunc)pcf_property_get ) /* get_property */
+
+
+ /*
+ *
+ * SERVICE LIST
+ *
+ */
+
+ static const FT_ServiceDescRec pcf_services[] =
+ {
+ { FT_SERVICE_ID_BDF, &pcf_service_bdf },
+ { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF },
+ { FT_SERVICE_ID_PROPERTIES, &pcf_service_properties },
+ { NULL, NULL }
+ };
+
+
+ FT_CALLBACK_DEF( FT_Module_Interface )
+ pcf_driver_requester( FT_Module module,
+ const char* name )
+ {
+ FT_UNUSED( module );
+
+ return ft_service_list_lookup( pcf_services, name );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_driver_init( FT_Module module ) /* PCF_Driver */
+ {
+#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
+ PCF_Driver driver = (PCF_Driver)module;
+
+
+ driver->no_long_family_names = 0;
+#else
+ FT_UNUSED( module );
+#endif
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pcf_driver_done( FT_Module module ) /* PCF_Driver */
+ {
+ FT_UNUSED( module );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec pcf_driver_class =
+ {
+ {
+ FT_MODULE_FONT_DRIVER |
+ FT_MODULE_DRIVER_NO_OUTLINES,
+
+ sizeof ( PCF_DriverRec ),
+ "pcf",
+ 0x10000L,
+ 0x20000L,
+
+ NULL, /* module-specific interface */
+
+ pcf_driver_init, /* FT_Module_Constructor module_init */
+ pcf_driver_done, /* FT_Module_Destructor module_done */
+ pcf_driver_requester /* FT_Module_Requester get_interface */
+ },
+
+ sizeof ( PCF_FaceRec ),
+ sizeof ( FT_SizeRec ),
+ sizeof ( FT_GlyphSlotRec ),
+
+ PCF_Face_Init, /* FT_Face_InitFunc init_face */
+ PCF_Face_Done, /* FT_Face_DoneFunc done_face */
+ NULL, /* FT_Size_InitFunc init_size */
+ NULL, /* FT_Size_DoneFunc done_size */
+ NULL, /* FT_Slot_InitFunc init_slot */
+ NULL, /* FT_Slot_DoneFunc done_slot */
+
+ PCF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */
+
+ NULL, /* FT_Face_GetKerningFunc get_kerning */
+ NULL, /* FT_Face_AttachFunc attach_file */
+ NULL, /* FT_Face_GetAdvancesFunc get_advances */
+
+ PCF_Size_Request, /* FT_Size_RequestFunc request_size */
+ PCF_Size_Select /* FT_Size_SelectFunc select_size */
+ };
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfdrivr.h b/modules/freetype2/src/pcf/pcfdrivr.h
new file mode 100644
index 0000000000..d465393743
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfdrivr.h
@@ -0,0 +1,44 @@
+/* pcfdrivr.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef PCFDRIVR_H_
+#define PCFDRIVR_H_
+
+#include <freetype/internal/ftdrv.h>
+
+
+FT_BEGIN_HEADER
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* PCFDRIVR_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcferror.h b/modules/freetype2/src/pcf/pcferror.h
new file mode 100644
index 0000000000..8b9e9902a3
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcferror.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ *
+ * pcferror.h
+ *
+ * PCF error codes (specification only).
+ *
+ * Copyright 2001, 2012 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 PCF error enumeration constants.
+ *
+ */
+
+#ifndef PCFERROR_H_
+#define PCFERROR_H_
+
+#include <freetype/ftmoderr.h>
+
+#undef FTERRORS_H_
+
+#undef FT_ERR_PREFIX
+#define FT_ERR_PREFIX PCF_Err_
+#define FT_ERR_BASE FT_Mod_Err_PCF
+
+#include <freetype/fterrors.h>
+
+#endif /* PCFERROR_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfread.c b/modules/freetype2/src/pcf/pcfread.c
new file mode 100644
index 0000000000..f167bcb8ae
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfread.c
@@ -0,0 +1,1731 @@
+/* pcfread.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2010, 2012-2014 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/ftobjs.h>
+
+#include "pcf.h"
+#include "pcfread.h"
+
+#include "pcferror.h"
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT pcfread
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ static const char* const tableNames[] =
+ {
+ "properties",
+ "accelerators",
+ "metrics",
+ "bitmaps",
+ "ink metrics",
+ "encodings",
+ "swidths",
+ "glyph names",
+ "BDF accelerators"
+ };
+#endif
+
+
+ static
+ const FT_Frame_Field pcf_toc_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TocRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_ULONG_LE( version ),
+ FT_FRAME_ULONG_LE( count ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_table_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TableRec
+
+ FT_FRAME_START( 16 ),
+ FT_FRAME_ULONG_LE( type ),
+ FT_FRAME_ULONG_LE( format ),
+ FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */
+ FT_FRAME_ULONG_LE( offset ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_read_TOC( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ PCF_Toc toc = &face->toc;
+ PCF_Table tables;
+
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_UInt n;
+
+ FT_ULong size;
+
+
+ if ( FT_STREAM_SEEK( 0 ) ||
+ FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) )
+ return FT_THROW( Cannot_Open_Resource );
+
+ if ( toc->version != PCF_FILE_VERSION ||
+ toc->count == 0 )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( stream->size < 16 )
+ return FT_THROW( Invalid_File_Format );
+
+ /* we need 16 bytes per TOC entry, */
+ /* and there can be most 9 tables */
+ if ( toc->count > ( stream->size >> 4 ) ||
+ toc->count > 9 )
+ {
+ FT_TRACE0(( "pcf_read_TOC: adjusting number of tables"
+ " (from %ld to %ld)\n",
+ toc->count,
+ FT_MIN( stream->size >> 4, 9 ) ));
+ toc->count = FT_MIN( stream->size >> 4, 9 );
+ }
+
+ if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) )
+ return error;
+
+ tables = face->toc.tables;
+ for ( n = 0; n < toc->count; n++ )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
+ goto Exit;
+ tables++;
+ }
+
+ /* Sort tables and check for overlaps. Because they are almost */
+ /* always ordered already, an in-place bubble sort with simultaneous */
+ /* boundary checking seems appropriate. */
+ tables = face->toc.tables;
+
+ for ( n = 0; n < toc->count - 1; n++ )
+ {
+ FT_UInt i, have_change;
+
+
+ have_change = 0;
+
+ for ( i = 0; i < toc->count - 1 - n; i++ )
+ {
+ PCF_TableRec tmp;
+
+
+ if ( tables[i].offset > tables[i + 1].offset )
+ {
+ tmp = tables[i];
+ tables[i] = tables[i + 1];
+ tables[i + 1] = tmp;
+
+ have_change = 1;
+ }
+
+ if ( ( tables[i].size > tables[i + 1].offset ) ||
+ ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
+ {
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+ }
+
+ if ( !have_change )
+ break;
+ }
+
+ /*
+ * We now check whether the `size' and `offset' values are reasonable:
+ * `offset' + `size' must not exceed the stream size.
+ *
+ * Note, however, that X11's `pcfWriteFont' routine (used by the
+ * `bdftopcf' program to create PCF font files) has two special
+ * features.
+ *
+ * - It always assigns the accelerator table a size of 100 bytes in the
+ * TOC, regardless of its real size, which can vary between 34 and 72
+ * bytes.
+ *
+ * - Due to the way the routine is designed, it ships out the last font
+ * table with its real size, ignoring the TOC's size value. Since
+ * the TOC size values are always rounded up to a multiple of 4, the
+ * difference can be up to three bytes for all tables except the
+ * accelerator table, for which the difference can be as large as 66
+ * bytes.
+ *
+ */
+
+ tables = face->toc.tables;
+ size = stream->size;
+
+ for ( n = 0; n < toc->count - 1; n++ )
+ {
+ /* we need two checks to avoid overflow */
+ if ( ( tables->size > size ) ||
+ ( tables->offset > size - tables->size ) )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+ tables++;
+ }
+
+ /* only check `tables->offset' for last table element ... */
+ if ( ( tables->offset > size ) )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+ /* ... and adjust `tables->size' to the real value if necessary */
+ if ( tables->size > size - tables->offset )
+ tables->size = size - tables->offset;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ {
+ FT_UInt i, j;
+ const char* name = "?";
+
+
+ FT_TRACE4(( "pcf_read_TOC:\n" ));
+
+ FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
+
+ tables = face->toc.tables;
+ for ( i = 0; i < toc->count; i++ )
+ {
+ for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
+ j++ )
+ if ( tables[i].type == 1UL << j )
+ name = tableNames[j];
+
+ FT_TRACE4(( " %d: type=%s, format=0x%lX,"
+ " size=%ld (0x%lX), offset=%ld (0x%lX)\n",
+ i, name,
+ tables[i].format,
+ tables[i].size, tables[i].size,
+ tables[i].offset, tables[i].offset ));
+ }
+ }
+
+#endif
+
+ return FT_Err_Ok;
+
+ Exit:
+ FT_FREE( face->toc.tables );
+ return error;
+ }
+
+
+#define PCF_METRIC_SIZE 12
+
+ static
+ const FT_Frame_Field pcf_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( PCF_METRIC_SIZE ),
+ FT_FRAME_SHORT_LE( leftSideBearing ),
+ FT_FRAME_SHORT_LE( rightSideBearing ),
+ FT_FRAME_SHORT_LE( characterWidth ),
+ FT_FRAME_SHORT_LE( ascent ),
+ FT_FRAME_SHORT_LE( descent ),
+ FT_FRAME_SHORT_LE( attributes ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_metric_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( PCF_METRIC_SIZE ),
+ FT_FRAME_SHORT( leftSideBearing ),
+ FT_FRAME_SHORT( rightSideBearing ),
+ FT_FRAME_SHORT( characterWidth ),
+ FT_FRAME_SHORT( ascent ),
+ FT_FRAME_SHORT( descent ),
+ FT_FRAME_SHORT( attributes ),
+ FT_FRAME_END
+ };
+
+
+#define PCF_COMPRESSED_METRIC_SIZE 5
+
+ static
+ const FT_Frame_Field pcf_compressed_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_Compressed_MetricRec
+
+ FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
+ FT_FRAME_BYTE( leftSideBearing ),
+ FT_FRAME_BYTE( rightSideBearing ),
+ FT_FRAME_BYTE( characterWidth ),
+ FT_FRAME_BYTE( ascent ),
+ FT_FRAME_BYTE( descent ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_metric( FT_Stream stream,
+ FT_ULong format,
+ PCF_Metric metric )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ const FT_Frame_Field* fields;
+
+
+ /* parsing normal metrics */
+ fields = ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ ? pcf_metric_msb_header
+ : pcf_metric_header;
+
+ /* the following sets `error' but doesn't return in case of failure */
+ (void)FT_STREAM_READ_FIELDS( fields, metric );
+ }
+ else
+ {
+ PCF_Compressed_MetricRec compr;
+
+
+ /* parsing compressed metrics */
+ if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
+ goto Exit;
+
+ metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
+ metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
+ metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
+ metric->ascent = (FT_Short)( compr.ascent - 0x80 );
+ metric->descent = (FT_Short)( compr.descent - 0x80 );
+ metric->attributes = 0;
+ }
+
+ FT_TRACE5(( " width=%d,"
+ " lsb=%d, rsb=%d,"
+ " ascent=%d, descent=%d,"
+ " attributes=%d\n",
+ metric->characterWidth,
+ metric->leftSideBearing,
+ metric->rightSideBearing,
+ metric->ascent,
+ metric->descent,
+ metric->attributes ));
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_seek_to_table_type( FT_Stream stream,
+ PCF_Table tables,
+ FT_ULong ntables, /* same as PCF_Toc->count */
+ FT_ULong type,
+ FT_ULong *aformat,
+ FT_ULong *asize )
+ {
+ FT_Error error = FT_ERR( Invalid_File_Format );
+ FT_ULong i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ {
+ if ( stream->pos > tables[i].offset )
+ {
+ error = FT_THROW( Invalid_Stream_Skip );
+ goto Fail;
+ }
+
+ if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
+ {
+ error = FT_THROW( Invalid_Stream_Skip );
+ goto Fail;
+ }
+
+ *asize = tables[i].size;
+ *aformat = tables[i].format;
+
+ return FT_Err_Ok;
+ }
+
+ Fail:
+ *asize = 0;
+ return error;
+ }
+
+
+ static FT_Bool
+ pcf_has_table_type( PCF_Table tables,
+ FT_ULong ntables, /* same as PCF_Toc->count */
+ FT_ULong type )
+ {
+ FT_ULong i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ return TRUE;
+
+ return FALSE;
+ }
+
+
+#define PCF_PROPERTY_SIZE 9
+
+ static
+ const FT_Frame_Field pcf_property_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( PCF_PROPERTY_SIZE ),
+ FT_FRAME_LONG_LE( name ),
+ FT_FRAME_BYTE ( isString ),
+ FT_FRAME_LONG_LE( value ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_property_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( PCF_PROPERTY_SIZE ),
+ FT_FRAME_LONG( name ),
+ FT_FRAME_BYTE( isString ),
+ FT_FRAME_LONG( value ),
+ FT_FRAME_END
+ };
+
+
+ FT_LOCAL_DEF( PCF_Property )
+ pcf_find_property( PCF_Face face,
+ const FT_String* prop )
+ {
+ PCF_Property properties = face->properties;
+ FT_Bool found = 0;
+ int i;
+
+
+ for ( i = 0; i < face->nprops && !found; i++ )
+ {
+ if ( !ft_strcmp( properties[i].name, prop ) )
+ found = 1;
+ }
+
+ if ( found )
+ return properties + i - 1;
+ else
+ return NULL;
+ }
+
+
+ static FT_Error
+ pcf_get_properties( FT_Stream stream,
+ PCF_Face face )
+ {
+ PCF_ParseProperty props = NULL;
+ PCF_Property properties = NULL;
+ FT_ULong nprops, orig_nprops, i;
+ FT_ULong format, size;
+ FT_Error error;
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_ULong string_size;
+ FT_String* strings = NULL;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_PROPERTIES,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ if ( FT_READ_ULONG_LE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "pcf_get_properties:\n" ));
+ FT_TRACE4(( " format: 0x%lX (%s)\n",
+ format,
+ PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( orig_nprops );
+ else
+ (void)FT_READ_ULONG_LE( orig_nprops );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( " number of properties: %ld\n", orig_nprops ));
+
+ /* rough estimate */
+ if ( orig_nprops > size / PCF_PROPERTY_SIZE )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Bail;
+ }
+
+ /* as a heuristic limit to avoid excessive allocation in */
+ /* gzip bombs (i.e., very small, invalid input data that */
+ /* pretends to expand to an insanely large file) we only */
+ /* load the first 256 properties */
+ if ( orig_nprops > 256 )
+ {
+ FT_TRACE0(( "pcf_get_properties:"
+ " only loading first 256 properties\n" ));
+ nprops = 256;
+ }
+ else
+ nprops = orig_nprops;
+
+ face->nprops = (int)nprops;
+
+ if ( FT_QNEW_ARRAY( props, nprops ) )
+ goto Bail;
+
+ for ( i = 0; i < nprops; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
+ goto Bail;
+ }
+ }
+
+ /* this skip will only work if we really have an extremely large */
+ /* number of properties; it will fail for fake data, avoiding an */
+ /* unnecessarily large allocation later on */
+ if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) )
+ {
+ error = FT_THROW( Invalid_Stream_Skip );
+ goto Bail;
+ }
+
+ /* pad the property array */
+ /* */
+ /* clever here - nprops is the same as the number of odd-units read, */
+ /* as only isStringProp are odd length (Keith Packard) */
+ /* */
+ if ( orig_nprops & 3 )
+ {
+ i = 4 - ( orig_nprops & 3 );
+ if ( FT_STREAM_SKIP( i ) )
+ {
+ error = FT_THROW( Invalid_Stream_Skip );
+ goto Bail;
+ }
+ }
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( string_size );
+ else
+ (void)FT_READ_ULONG_LE( string_size );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( " string size: %ld\n", string_size ));
+
+ /* rough estimate */
+ if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE )
+ {
+ error = FT_THROW( Invalid_Table );
+ goto Bail;
+ }
+
+ /* the strings in the `strings' array are PostScript strings, */
+ /* which can have a maximum length of 65536 characters each */
+ if ( string_size > 16777472 ) /* 256 * (65536 + 1) */
+ {
+ FT_TRACE0(( "pcf_get_properties:"
+ " loading only 16777472 bytes of strings array\n" ));
+ string_size = 16777472;
+ }
+
+ /* allocate one more byte so that we have a final null byte */
+ if ( FT_QALLOC( strings, string_size + 1 ) ||
+ FT_STREAM_READ( strings, string_size ) )
+ goto Bail;
+
+ strings[string_size] = '\0';
+
+ /* zero out in case of failure */
+ if ( FT_NEW_ARRAY( properties, nprops ) )
+ goto Bail;
+
+ face->properties = properties;
+
+ FT_TRACE4(( "\n" ));
+ for ( i = 0; i < nprops; i++ )
+ {
+ FT_Long name_offset = props[i].name;
+
+
+ if ( ( name_offset < 0 ) ||
+ ( (FT_ULong)name_offset > string_size ) )
+ {
+ error = FT_THROW( Invalid_Offset );
+ goto Bail;
+ }
+
+ if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
+ goto Bail;
+
+ FT_TRACE4(( " %s:", properties[i].name ));
+
+ properties[i].isString = props[i].isString;
+
+ if ( props[i].isString )
+ {
+ FT_Long value_offset = props[i].value;
+
+
+ if ( ( value_offset < 0 ) ||
+ ( (FT_ULong)value_offset > string_size ) )
+ {
+ error = FT_THROW( Invalid_Offset );
+ goto Bail;
+ }
+
+ if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
+ goto Bail;
+
+ FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
+ }
+ else
+ {
+ properties[i].value.l = props[i].value;
+
+ FT_TRACE4(( " %ld\n", properties[i].value.l ));
+ }
+ }
+
+ error = FT_Err_Ok;
+
+ Bail:
+ FT_FREE( props );
+ FT_FREE( strings );
+
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_metrics( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_ULong format, size;
+ PCF_Metric metrics = NULL;
+ FT_ULong nmetrics, orig_nmetrics, i;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_METRICS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ if ( FT_READ_ULONG_LE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "pcf_get_metrics:\n" ));
+ FT_TRACE4(( " format: 0x%lX (%s, %s)\n",
+ format,
+ PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
+ PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ?
+ "compressed" : "uncompressed" ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( orig_nmetrics );
+ else
+ (void)FT_READ_ULONG_LE( orig_nmetrics );
+ }
+ else
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_USHORT( orig_nmetrics );
+ else
+ (void)FT_READ_USHORT_LE( orig_nmetrics );
+ }
+ if ( error )
+ return FT_THROW( Invalid_File_Format );
+
+ FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics ));
+
+ /* rough estimate */
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ if ( orig_nmetrics > size / PCF_METRIC_SIZE )
+ return FT_THROW( Invalid_Table );
+ }
+ else
+ {
+ if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
+ return FT_THROW( Invalid_Table );
+ }
+
+ if ( !orig_nmetrics )
+ return FT_THROW( Invalid_Table );
+
+ /*
+ * PCF is a format from ancient times; Unicode was in its infancy, and
+ * widely used two-byte character sets for CJK scripts (Big 5, GB 2312,
+ * JIS X 0208, etc.) did have at most 15000 characters. Even the more
+ * exotic CNS 11643 and CCCII standards, which were essentially
+ * three-byte character sets, provided less then 65536 assigned
+ * characters.
+ *
+ * While technically possible to have a larger number of glyphs in PCF
+ * files, we thus limit the number to 65535, taking into account that we
+ * synthesize the metrics of glyph 0 to be a copy of the `default
+ * character', and that 0xFFFF in the encodings array indicates a
+ * missing glyph.
+ */
+ if ( orig_nmetrics > 65534 )
+ {
+ FT_TRACE0(( "pcf_get_metrics:"
+ " only loading first 65534 metrics\n" ));
+ nmetrics = 65534;
+ }
+ else
+ nmetrics = orig_nmetrics;
+
+ face->nmetrics = nmetrics + 1;
+
+ if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) )
+ return error;
+
+ /* we handle glyph index 0 later on */
+ metrics = face->metrics + 1;
+
+ FT_TRACE4(( "\n" ));
+ for ( i = 1; i < face->nmetrics; i++, metrics++ )
+ {
+ FT_TRACE5(( " idx %ld:", i ));
+ error = pcf_get_metric( stream, format, metrics );
+
+ metrics->bits = 0;
+
+ if ( error )
+ break;
+
+ /* sanity checks -- those values are used in `PCF_Glyph_Load' to */
+ /* compute a glyph's bitmap dimensions, thus setting them to zero in */
+ /* case of an error disables this particular glyph only */
+ if ( metrics->rightSideBearing < metrics->leftSideBearing ||
+ metrics->ascent < -metrics->descent )
+ {
+ metrics->characterWidth = 0;
+ metrics->leftSideBearing = 0;
+ metrics->rightSideBearing = 0;
+ metrics->ascent = 0;
+ metrics->descent = 0;
+
+ FT_TRACE0(( "pcf_get_metrics:"
+ " invalid metrics for glyph %ld\n", i ));
+ }
+ }
+
+ if ( error )
+ FT_FREE( face->metrics );
+
+ Bail:
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_bitmaps( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ FT_ULong bitmapSizes[GLYPHPADOPTIONS];
+ FT_ULong format, size, pos;
+ FT_ULong nbitmaps, orig_nbitmaps, i, sizebitmaps = 0;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BITMAPS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_Stream_EnterFrame( stream, 8 );
+ if ( error )
+ return error;
+
+ format = FT_GET_ULONG_LE();
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ orig_nbitmaps = FT_GET_ULONG();
+ else
+ orig_nbitmaps = FT_GET_ULONG_LE();
+
+ FT_Stream_ExitFrame( stream );
+
+ FT_TRACE4(( "pcf_get_bitmaps:\n" ));
+ FT_TRACE4(( " format: 0x%lX\n", format ));
+ FT_TRACE4(( " (%s, %s,\n",
+ PCF_BYTE_ORDER( format ) == MSBFirst
+ ? "most significant byte first"
+ : "least significant byte first",
+ PCF_BIT_ORDER( format ) == MSBFirst
+ ? "most significant bit first"
+ : "least significant bit first" ));
+ FT_TRACE4(( " padding=%d bit%s, scanning=%d bit%s)\n",
+ 8 << PCF_GLYPH_PAD_INDEX( format ),
+ ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s",
+ 8 << PCF_SCAN_UNIT_INDEX( format ),
+ ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ return FT_THROW( Invalid_File_Format );
+
+ FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps ));
+
+ /* see comment in `pcf_get_metrics' */
+ if ( orig_nbitmaps > 65534 )
+ {
+ FT_TRACE0(( "pcf_get_bitmaps:"
+ " only loading first 65534 bitmaps\n" ));
+ nbitmaps = 65534;
+ }
+ else
+ nbitmaps = orig_nbitmaps;
+
+ /* no extra bitmap for glyph 0 */
+ if ( nbitmaps != face->nmetrics - 1 )
+ return FT_THROW( Invalid_File_Format );
+
+ /* start position of bitmap data */
+ pos = stream->pos + nbitmaps * 4 + 4 * 4;
+
+ FT_TRACE5(( "\n" ));
+ for ( i = 1; i <= nbitmaps; i++ )
+ {
+ FT_ULong offset;
+
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( offset );
+ else
+ (void)FT_READ_ULONG_LE( offset );
+
+ FT_TRACE5(( " bitmap %lu: offset %lu (0x%lX)\n",
+ i, offset, offset ));
+
+ /* right now, we only check the offset with a rough estimate; */
+ /* actual bitmaps are only loaded on demand */
+ if ( offset > size )
+ {
+ FT_TRACE0(( "pcf_get_bitmaps:"
+ " invalid offset to bitmap data of glyph %lu\n", i ));
+ face->metrics[i].bits = pos;
+ }
+ else
+ face->metrics[i].bits = pos + offset;
+ }
+ if ( error )
+ goto Bail;
+
+ for ( i = 0; i < GLYPHPADOPTIONS; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( bitmapSizes[i] );
+ else
+ (void)FT_READ_ULONG_LE( bitmapSizes[i] );
+ if ( error )
+ goto Bail;
+
+ sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
+
+ FT_TRACE4(( " %d-bit padding implies a size of %lu\n",
+ 8 << i, bitmapSizes[i] ));
+ }
+
+ FT_TRACE4(( " %lu bitmaps, using %d-bit padding\n",
+ nbitmaps,
+ 8 << PCF_GLYPH_PAD_INDEX( format ) ));
+ FT_TRACE4(( " bitmap size: %lu\n", sizebitmaps ));
+
+ FT_UNUSED( sizebitmaps ); /* only used for debugging */
+
+ face->bitmapsFormat = format;
+
+ Bail:
+ return error;
+ }
+
+
+ /*
+ * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
+ * is the same as a character code in FreeType speak.
+ */
+#define PCF_ENC_SIZE 10
+
+ static
+ const FT_Frame_Field pcf_enc_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_EncRec
+
+ FT_FRAME_START( PCF_ENC_SIZE ),
+ FT_FRAME_USHORT_LE( firstCol ),
+ FT_FRAME_USHORT_LE( lastCol ),
+ FT_FRAME_USHORT_LE( firstRow ),
+ FT_FRAME_USHORT_LE( lastRow ),
+ FT_FRAME_USHORT_LE( defaultChar ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_enc_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_EncRec
+
+ FT_FRAME_START( PCF_ENC_SIZE ),
+ FT_FRAME_USHORT( firstCol ),
+ FT_FRAME_USHORT( lastCol ),
+ FT_FRAME_USHORT( firstRow ),
+ FT_FRAME_USHORT( lastRow ),
+ FT_FRAME_USHORT( defaultChar ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_encodings( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_ULong format, size;
+ PCF_Enc enc = &face->enc;
+ FT_ULong nencoding;
+ FT_UShort* offset;
+ FT_UShort defaultCharRow, defaultCharCol;
+ FT_UShort encodingOffset, defaultCharEncodingOffset;
+ FT_UShort i, j;
+ FT_Byte* pos;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ENCODINGS,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ if ( FT_READ_ULONG_LE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "pcf_get_encodings:\n" ));
+ FT_TRACE4(( " format: 0x%lX (%s)\n",
+ format,
+ PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS ) )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) )
+ goto Bail;
+ }
+
+ FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n",
+ enc->firstCol, enc->lastCol ));
+ FT_TRACE4(( " firstRow 0x%X, lastRow 0x%X\n",
+ enc->firstRow, enc->lastRow ));
+ FT_TRACE4(( " defaultChar 0x%X\n",
+ enc->defaultChar ));
+
+ /* sanity checks; we limit numbers of rows and columns to 256 */
+ if ( enc->firstCol > enc->lastCol ||
+ enc->lastCol > 0xFF ||
+ enc->firstRow > enc->lastRow ||
+ enc->lastRow > 0xFF )
+ return FT_THROW( Invalid_Table );
+
+ FT_TRACE5(( "\n" ));
+
+ defaultCharRow = enc->defaultChar >> 8;
+ defaultCharCol = enc->defaultChar & 0xFF;
+
+ /* validate default character */
+ if ( defaultCharRow < enc->firstRow ||
+ defaultCharRow > enc->lastRow ||
+ defaultCharCol < enc->firstCol ||
+ defaultCharCol > enc->lastCol )
+ {
+ enc->defaultChar = enc->firstRow * 256U + enc->firstCol;
+ FT_TRACE0(( "pcf_get_encodings:"
+ " Invalid default character set to %u\n",
+ enc->defaultChar ));
+
+ defaultCharRow = enc->firstRow;
+ defaultCharCol = enc->firstCol;
+ }
+
+ nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) *
+ (FT_ULong)( enc->lastRow - enc->firstRow + 1 );
+
+ error = FT_Stream_EnterFrame( stream, 2 * nencoding );
+ if ( error )
+ goto Bail;
+
+ /*
+ * FreeType mandates that glyph index 0 is the `undefined glyph', which
+ * PCF calls the `default character'. However, FreeType needs glyph
+ * index 0 to be used for the undefined glyph only, which is is not the
+ * case for PCF. For this reason, we add one slot for glyph index 0 and
+ * simply copy the default character to it.
+ *
+ * `stream->cursor' still points to the beginning of the frame; we can
+ * thus easily get the offset to the default character.
+ */
+ pos = stream->cursor +
+ 2 * ( ( defaultCharRow - enc->firstRow ) *
+ ( enc->lastCol - enc->firstCol + 1 ) +
+ defaultCharCol - enc->firstCol );
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ defaultCharEncodingOffset = FT_PEEK_USHORT( pos );
+ else
+ defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos );
+
+ if ( defaultCharEncodingOffset == 0xFFFF )
+ {
+ FT_TRACE0(( "pcf_get_encodings:"
+ " No glyph for default character,\n" ));
+ FT_TRACE0(( " "
+ " setting it to the first glyph of the font\n" ));
+ defaultCharEncodingOffset = 1;
+ }
+ else
+ {
+ defaultCharEncodingOffset++;
+
+ if ( defaultCharEncodingOffset >= face->nmetrics )
+ {
+ FT_TRACE0(( "pcf_get_encodings:"
+ " Invalid glyph index for default character,\n" ));
+ FT_TRACE0(( " "
+ " setting it to the first glyph of the font\n" ));
+ defaultCharEncodingOffset = 1;
+ }
+ }
+
+ /* copy metrics of default character to index 0 */
+ face->metrics[0] = face->metrics[defaultCharEncodingOffset];
+
+ if ( FT_QNEW_ARRAY( enc->offset, nencoding ) )
+ goto Bail;
+
+ /* now loop over all values */
+ offset = enc->offset;
+ for ( i = enc->firstRow; i <= enc->lastRow; i++ )
+ {
+ for ( j = enc->firstCol; j <= enc->lastCol; j++ )
+ {
+ /* X11's reference implementation uses the equivalent to */
+ /* `FT_GET_SHORT', however PCF fonts with more than 32768 */
+ /* characters (e.g., `unifont.pcf') clearly show that an */
+ /* unsigned value is needed. */
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ encodingOffset = FT_GET_USHORT();
+ else
+ encodingOffset = FT_GET_USHORT_LE();
+
+ /* everything is off by 1 due to the artificial glyph 0 */
+ *offset++ = encodingOffset == 0xFFFF ? 0xFFFF
+ : encodingOffset + 1;
+ }
+ }
+ FT_Stream_ExitFrame( stream );
+
+ Bail:
+ return error;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_accel_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG_LE ( fontAscent ),
+ FT_FRAME_LONG_LE ( fontDescent ),
+ FT_FRAME_LONG_LE ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_accel_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG ( fontAscent ),
+ FT_FRAME_LONG ( fontDescent ),
+ FT_FRAME_LONG ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_accel( FT_Stream stream,
+ PCF_Face face,
+ FT_ULong type )
+ {
+ FT_ULong format, size;
+ FT_Error error;
+ PCF_Accel accel = &face->accel;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ type,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ if ( FT_READ_ULONG_LE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "pcf_get_accel%s:\n",
+ type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)"
+ : "" ));
+ FT_TRACE4(( " format: 0x%lX (%s, %s)\n",
+ format,
+ PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
+ PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ?
+ "accelerated" : "not accelerated" ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
+ goto Bail;
+ }
+
+ FT_TRACE5(( " noOverlap=%s, constantMetrics=%s,"
+ " terminalFont=%s, constantWidth=%s\n",
+ accel->noOverlap ? "yes" : "no",
+ accel->constantMetrics ? "yes" : "no",
+ accel->terminalFont ? "yes" : "no",
+ accel->constantWidth ? "yes" : "no" ));
+ FT_TRACE5(( " inkInside=%s, inkMetrics=%s, drawDirection=%s\n",
+ accel->inkInside ? "yes" : "no",
+ accel->inkMetrics ? "yes" : "no",
+ accel->drawDirection ? "RTL" : "LTR" ));
+ FT_TRACE5(( " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n",
+ accel->fontAscent,
+ accel->fontDescent,
+ accel->maxOverlap ));
+
+ /* sanity checks */
+ if ( FT_ABS( accel->fontAscent ) > 0x7FFF )
+ {
+ accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF;
+ FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n",
+ accel->fontAscent ));
+ }
+ if ( FT_ABS( accel->fontDescent ) > 0x7FFF )
+ {
+ accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF;
+ FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n",
+ accel->fontDescent ));
+ }
+
+ FT_TRACE5(( " minbounds:" ));
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->minbounds) );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE5(( " maxbounds:" ));
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->maxbounds) );
+ if ( error )
+ goto Bail;
+
+ if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ {
+ FT_TRACE5(( " ink minbounds:" ));
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->ink_minbounds) );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE5(( " ink maxbounds:" ));
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->ink_maxbounds) );
+ if ( error )
+ goto Bail;
+ }
+ else
+ {
+ accel->ink_minbounds = accel->minbounds;
+ accel->ink_maxbounds = accel->maxbounds;
+ }
+
+ Bail:
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_interpret_style( PCF_Face pcf )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Face face = FT_FACE( pcf );
+ FT_Memory memory = face->memory;
+
+ PCF_Property prop;
+
+ const char* strings[4] = { NULL, NULL, NULL, NULL };
+ size_t lengths[4], nn, len;
+
+
+ face->style_flags = 0;
+
+ prop = pcf_find_property( pcf, "SLANT" );
+ if ( prop && prop->isString &&
+ ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
+ *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
+ {
+ face->style_flags |= FT_STYLE_FLAG_ITALIC;
+ strings[2] = ( *(prop->value.atom) == 'O' ||
+ *(prop->value.atom) == 'o' ) ? "Oblique"
+ : "Italic";
+ }
+
+ prop = pcf_find_property( pcf, "WEIGHT_NAME" );
+ if ( prop && prop->isString &&
+ ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
+ {
+ face->style_flags |= FT_STYLE_FLAG_BOLD;
+ strings[1] = "Bold";
+ }
+
+ prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
+ if ( prop && prop->isString &&
+ *(prop->value.atom) &&
+ !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
+ strings[3] = (const char*)( prop->value.atom );
+
+ prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
+ if ( prop && prop->isString &&
+ *(prop->value.atom) &&
+ !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
+ strings[0] = (const char*)( prop->value.atom );
+
+ for ( len = 0, nn = 0; nn < 4; nn++ )
+ {
+ lengths[nn] = 0;
+ if ( strings[nn] )
+ {
+ lengths[nn] = ft_strlen( strings[nn] );
+ len += lengths[nn] + 1;
+ }
+ }
+
+ if ( len == 0 )
+ {
+ strings[0] = "Regular";
+ lengths[0] = ft_strlen( strings[0] );
+ len = lengths[0] + 1;
+ }
+
+ {
+ char* s;
+
+
+ if ( FT_QALLOC( face->style_name, len ) )
+ return error;
+
+ s = face->style_name;
+
+ for ( nn = 0; nn < 4; nn++ )
+ {
+ const char* src = strings[nn];
+
+
+ len = lengths[nn];
+
+ if ( !src )
+ continue;
+
+ /* separate elements with a space */
+ if ( s != face->style_name )
+ *s++ = ' ';
+
+ ft_memcpy( s, src, len );
+
+ /* need to convert spaces to dashes for */
+ /* add_style_name and setwidth_name */
+ if ( nn == 0 || nn == 3 )
+ {
+ size_t mm;
+
+
+ for ( mm = 0; mm < len; mm++ )
+ if ( s[mm] == ' ' )
+ s[mm] = '-';
+ }
+
+ s += len;
+ }
+ *s = 0;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pcf_load_font( FT_Stream stream,
+ PCF_Face face,
+ FT_Long face_index )
+ {
+ FT_Face root = FT_FACE( face );
+ FT_Error error;
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_Bool hasBDFAccelerators;
+
+
+ error = pcf_read_TOC( stream, face );
+ if ( error )
+ goto Exit;
+
+ root->num_faces = 1;
+ root->face_index = 0;
+
+ /* If we are performing a simple font format check, exit immediately. */
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+
+ error = pcf_get_properties( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* Use the old accelerators if no BDF accelerators are in the file. */
+ hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ACCELERATORS );
+ if ( !hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
+ if ( error )
+ goto Exit;
+ }
+
+ /* metrics */
+ error = pcf_get_metrics( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* bitmaps */
+ error = pcf_get_bitmaps( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* encodings */
+ error = pcf_get_encodings( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
+ if ( hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
+ if ( error )
+ goto Exit;
+ }
+
+ /* XXX: TO DO: inkmetrics and glyph_names are missing */
+
+ /* now construct the face object */
+ {
+ PCF_Property prop;
+
+
+ root->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL;
+
+ if ( face->accel.constantWidth )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( FT_SET_ERROR( pcf_interpret_style( face ) ) )
+ goto Exit;
+
+ prop = pcf_find_property( face, "FAMILY_NAME" );
+ if ( prop && prop->isString )
+ {
+
+#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
+
+ PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face );
+
+
+ if ( !driver->no_long_family_names )
+ {
+ /* Prepend the foundry name plus a space to the family name. */
+ /* There are many fonts just called `Fixed' which look */
+ /* completely different, and which have nothing to do with each */
+ /* other. When selecting `Fixed' in KDE or Gnome one gets */
+ /* results that appear rather random, the style changes often if */
+ /* one changes the size and one cannot select some fonts at all. */
+ /* */
+ /* We also check whether we have `wide' characters; all put */
+ /* together, we get family names like `Sony Fixed' or `Misc */
+ /* Fixed Wide'. */
+
+ PCF_Property foundry_prop, point_size_prop, average_width_prop;
+
+ int l = ft_strlen( prop->value.atom ) + 1;
+ int wide = 0;
+
+
+ foundry_prop = pcf_find_property( face, "FOUNDRY" );
+ point_size_prop = pcf_find_property( face, "POINT_SIZE" );
+ average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" );
+
+ if ( point_size_prop && average_width_prop )
+ {
+ if ( average_width_prop->value.l >= point_size_prop->value.l )
+ {
+ /* This font is at least square shaped or even wider */
+ wide = 1;
+ l += ft_strlen( " Wide" );
+ }
+ }
+
+ if ( foundry_prop && foundry_prop->isString )
+ {
+ l += ft_strlen( foundry_prop->value.atom ) + 1;
+
+ if ( FT_QALLOC( root->family_name, l ) )
+ goto Exit;
+
+ ft_strcpy( root->family_name, foundry_prop->value.atom );
+ ft_strcat( root->family_name, " " );
+ ft_strcat( root->family_name, prop->value.atom );
+ }
+ else
+ {
+ if ( FT_QALLOC( root->family_name, l ) )
+ goto Exit;
+
+ ft_strcpy( root->family_name, prop->value.atom );
+ }
+
+ if ( wide )
+ ft_strcat( root->family_name, " Wide" );
+ }
+ else
+
+#endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+
+ {
+ if ( FT_STRDUP( root->family_name, prop->value.atom ) )
+ goto Exit;
+ }
+ }
+ else
+ root->family_name = NULL;
+
+ root->num_glyphs = (FT_Long)face->nmetrics;
+
+ root->num_fixed_sizes = 1;
+ if ( FT_NEW( root->available_sizes ) )
+ goto Exit;
+
+ {
+ FT_Bitmap_Size* bsize = root->available_sizes;
+ FT_Short resolution_x = 0, resolution_y = 0;
+
+
+ /* for simplicity, we take absolute values of integer properties */
+
+#if 0
+ bsize->height = face->accel.maxbounds.ascent << 6;
+#endif
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( face->accel.fontAscent + face->accel.fontDescent < 0 )
+ FT_TRACE0(( "pcf_load_font: negative height\n" ));
+#endif
+ if ( FT_ABS( face->accel.fontAscent +
+ face->accel.fontDescent ) > 0x7FFF )
+ {
+ bsize->height = 0x7FFF;
+ FT_TRACE0(( "pcf_load_font: clamping height to value %d\n",
+ bsize->height ));
+ }
+ else
+ bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent +
+ face->accel.fontDescent ) );
+
+ prop = pcf_find_property( face, "AVERAGE_WIDTH" );
+ if ( prop )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( prop->value.l < 0 )
+ FT_TRACE0(( "pcf_load_font: negative average width\n" ));
+#endif
+ if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) )
+ {
+ bsize->width = 0x7FFF;
+ FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n",
+ bsize->width ));
+ }
+ else
+ bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
+ }
+ else
+ {
+ /* this is a heuristical value */
+ bsize->width = ( bsize->height * 2 + 1 ) / 3;
+ }
+
+ prop = pcf_find_property( face, "POINT_SIZE" );
+ if ( prop )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( prop->value.l < 0 )
+ FT_TRACE0(( "pcf_load_font: negative point size\n" ));
+#endif
+ /* convert from 722.7 decipoints to 72 points per inch */
+ if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */
+ {
+ bsize->size = 0x7FFF;
+ FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n",
+ bsize->size ));
+ }
+ else
+ bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
+ 64 * 7200,
+ 72270L );
+ }
+
+ prop = pcf_find_property( face, "PIXEL_SIZE" );
+ if ( prop )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( prop->value.l < 0 )
+ FT_TRACE0(( "pcf_load_font: negative pixel size\n" ));
+#endif
+ if ( FT_ABS( prop->value.l ) > 0x7FFF )
+ {
+ bsize->y_ppem = 0x7FFF << 6;
+ FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n",
+ bsize->y_ppem ));
+ }
+ else
+ bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
+ }
+
+ prop = pcf_find_property( face, "RESOLUTION_X" );
+ if ( prop )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( prop->value.l < 0 )
+ FT_TRACE0(( "pcf_load_font: negative X resolution\n" ));
+#endif
+ if ( FT_ABS( prop->value.l ) > 0x7FFF )
+ {
+ resolution_x = 0x7FFF;
+ FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n",
+ resolution_x ));
+ }
+ else
+ resolution_x = FT_ABS( (FT_Short)prop->value.l );
+ }
+
+ prop = pcf_find_property( face, "RESOLUTION_Y" );
+ if ( prop )
+ {
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( prop->value.l < 0 )
+ FT_TRACE0(( "pcf_load_font: negative Y resolution\n" ));
+#endif
+ if ( FT_ABS( prop->value.l ) > 0x7FFF )
+ {
+ resolution_y = 0x7FFF;
+ FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n",
+ resolution_y ));
+ }
+ else
+ resolution_y = FT_ABS( (FT_Short)prop->value.l );
+ }
+
+ if ( bsize->y_ppem == 0 )
+ {
+ bsize->y_ppem = bsize->size;
+ if ( resolution_y )
+ bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
+ }
+ if ( resolution_x && resolution_y )
+ bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
+ resolution_x,
+ resolution_y );
+ else
+ bsize->x_ppem = bsize->y_ppem;
+ }
+
+ /* set up charset */
+ {
+ PCF_Property charset_registry, charset_encoding;
+
+
+ charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
+ charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
+
+ if ( charset_registry && charset_registry->isString &&
+ charset_encoding && charset_encoding->isString )
+ {
+ if ( FT_STRDUP( face->charset_encoding,
+ charset_encoding->value.atom ) ||
+ FT_STRDUP( face->charset_registry,
+ charset_registry->value.atom ) )
+ goto Exit;
+ }
+ }
+ }
+
+ Exit:
+ if ( error )
+ {
+ /* This is done to respect the behaviour of the original */
+ /* PCF font driver. */
+ error = FT_THROW( Invalid_File_Format );
+ }
+
+ return error;
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfread.h b/modules/freetype2/src/pcf/pcfread.h
new file mode 100644
index 0000000000..a54648fbf9
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfread.h
@@ -0,0 +1,44 @@
+/* pcfread.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2003 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef PCFREAD_H_
+#define PCFREAD_H_
+
+
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( PCF_Property )
+ pcf_find_property( PCF_Face face,
+ const FT_String* prop );
+
+FT_END_HEADER
+
+#endif /* PCFREAD_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfutil.c b/modules/freetype2/src/pcf/pcfutil.c
new file mode 100644
index 0000000000..9575726916
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfutil.c
@@ -0,0 +1,119 @@
+/*
+
+Copyright 1990, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */
+
+/*
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/* Modified for use with FreeType */
+
+
+#include "pcfutil.h"
+
+
+ /*
+ * Invert bit order within each BYTE of an array.
+ */
+
+ FT_LOCAL_DEF( void )
+ BitOrderInvert( unsigned char* buf,
+ size_t nbytes )
+ {
+ for ( ; nbytes > 0; nbytes--, buf++ )
+ {
+ unsigned int val = *buf;
+
+
+ val = ( ( val >> 1 ) & 0x55 ) | ( ( val << 1 ) & 0xAA );
+ val = ( ( val >> 2 ) & 0x33 ) | ( ( val << 2 ) & 0xCC );
+ val = ( ( val >> 4 ) & 0x0F ) | ( ( val << 4 ) & 0xF0 );
+
+ *buf = (unsigned char)val;
+ }
+ }
+
+
+#if defined( __clang__ ) || \
+ ( defined( __GNUC__ ) && \
+ ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 ) ) )
+
+#define BSWAP16( x ) __builtin_bswap16( x )
+#define BSWAP32( x ) __builtin_bswap32( x )
+
+#elif defined( _MSC_VER ) && _MSC_VER >= 1300
+
+#pragma intrinsic( _byteswap_ushort )
+#pragma intrinsic( _byteswap_ulong )
+
+#define BSWAP16( x ) _byteswap_ushort( x )
+#define BSWAP32( x ) _byteswap_ulong( x )
+
+#else
+
+#define BSWAP16( x ) \
+ (FT_UInt16)( ( ( ( x ) >> 8 ) & 0xff ) | \
+ ( ( ( x ) & 0xff ) << 8 ) )
+#define BSWAP32( x ) \
+ (FT_UInt32)( ( ( ( x ) & 0xff000000u ) >> 24 ) | \
+ ( ( ( x ) & 0x00ff0000u ) >> 8 ) | \
+ ( ( ( x ) & 0x0000ff00u ) << 8 ) | \
+ ( ( ( x ) & 0x000000ffu ) << 24 ) )
+
+#endif
+
+ /*
+ * Invert byte order within each 16-bits of an array.
+ */
+
+ FT_LOCAL_DEF( void )
+ TwoByteSwap( unsigned char* buf,
+ size_t nbytes )
+ {
+ FT_UInt16* b = (FT_UInt16*)buf;
+
+
+ for ( ; nbytes >= 2; nbytes -= 2, b++ )
+ *b = BSWAP16( *b );
+ }
+
+ /*
+ * Invert byte order within each 32-bits of an array.
+ */
+
+ FT_LOCAL_DEF( void )
+ FourByteSwap( unsigned char* buf,
+ size_t nbytes )
+ {
+ FT_UInt32* b = (FT_UInt32*)buf;
+
+
+ for ( ; nbytes >= 4; nbytes -= 4, b++ )
+ *b = BSWAP32( *b );
+ }
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/pcfutil.h b/modules/freetype2/src/pcf/pcfutil.h
new file mode 100644
index 0000000000..a197c15595
--- /dev/null
+++ b/modules/freetype2/src/pcf/pcfutil.h
@@ -0,0 +1,55 @@
+/* pcfutil.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000, 2001, 2004 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef PCFUTIL_H_
+#define PCFUTIL_H_
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include <freetype/internal/compiler-macros.h>
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( void )
+ BitOrderInvert( unsigned char* buf,
+ size_t nbytes );
+
+ FT_LOCAL( void )
+ TwoByteSwap( unsigned char* buf,
+ size_t nbytes );
+
+ FT_LOCAL( void )
+ FourByteSwap( unsigned char* buf,
+ size_t nbytes );
+
+FT_END_HEADER
+
+#endif /* PCFUTIL_H_ */
+
+
+/* END */
diff --git a/modules/freetype2/src/pcf/rules.mk b/modules/freetype2/src/pcf/rules.mk
new file mode 100644
index 0000000000..1b55daf4f4
--- /dev/null
+++ b/modules/freetype2/src/pcf/rules.mk
@@ -0,0 +1,82 @@
+#
+# FreeType 2 pcf driver configuration rules
+#
+
+
+# Copyright (C) 2000, 2001, 2003, 2008 by
+# Francesco Zappa Nardelli
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+# pcf driver directory
+#
+PCF_DIR := $(SRC_DIR)/pcf
+
+
+PCF_COMPILE := $(CC) $(ANSIFLAGS) \
+ $I$(subst /,$(COMPILER_SEP),$(PCF_DIR)) \
+ $(INCLUDE_FLAGS) \
+ $(FT_CFLAGS)
+
+
+# pcf driver sources (i.e., C files)
+#
+PCF_DRV_SRC := $(PCF_DIR)/pcfdrivr.c \
+ $(PCF_DIR)/pcfread.c \
+ $(PCF_DIR)/pcfutil.c
+
+# pcf driver headers
+#
+PCF_DRV_H := $(PCF_DRV_SRC:%.c=%.h) \
+ $(PCF_DIR)/pcf.h \
+ $(PCF_DIR)/pcferror.h
+
+# pcf driver object(s)
+#
+# PCF_DRV_OBJ_M is used during `multi' builds
+# PCF_DRV_OBJ_S is used during `single' builds
+#
+PCF_DRV_OBJ_M := $(PCF_DRV_SRC:$(PCF_DIR)/%.c=$(OBJ_DIR)/%.$O)
+PCF_DRV_OBJ_S := $(OBJ_DIR)/pcf.$O
+
+# pcf driver source file for single build
+#
+PCF_DRV_SRC_S := $(PCF_DIR)/pcf.c
+
+
+# pcf driver - single object
+#
+$(PCF_DRV_OBJ_S): $(PCF_DRV_SRC_S) $(PCF_DRV_SRC) $(FREETYPE_H) $(PCF_DRV_H)
+ $(PCF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(PCF_DRV_SRC_S))
+
+
+# pcf driver - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(PCF_DIR)/%.c $(FREETYPE_H) $(PCF_DRV_H)
+ $(PCF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(PCF_DRV_OBJ_S)
+DRV_OBJS_M += $(PCF_DRV_OBJ_M)
+
+
+# EOF