3 FreeType font driver for pcf files
5 Copyright (C) 2000-2004, 2006-2011, 2013, 2014 by
6 Francesco Zappa Nardelli
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include <freetype/internal/ftdebug.h>
30 #include <freetype/internal/ftstream.h>
31 #include <freetype/internal/ftobjs.h>
32 #include <freetype/ftgzip.h>
33 #include <freetype/ftlzw.h>
34 #include <freetype/ftbzip2.h>
35 #include <freetype/fterrors.h>
36 #include <freetype/ftbdf.h>
37 #include <freetype/ttnameid.h>
47 #define FT_COMPONENT pcfread
49 #include <freetype/internal/services/svbdf.h>
50 #include <freetype/internal/services/svfntfmt.h>
51 #include <freetype/internal/services/svprop.h>
52 #include <freetype/ftdriver.h>
55 /**************************************************************************
57 * The macro FT_COMPONENT is used in trace mode. It is an implicit
58 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
59 * messages during execution.
62 #define FT_COMPONENT pcfdriver
66 * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
67 * is the same as a `character code' in FreeType speak.
69 typedef struct PCF_CMapRec_
74 } PCF_CMapRec, *PCF_CMap;
77 FT_CALLBACK_DEF( FT_Error )
78 pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */
79 FT_Pointer init_data )
81 PCF_CMap pcfcmap = (PCF_CMap)cmap;
82 PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
84 FT_UNUSED( init_data );
87 pcfcmap->enc = &face->enc;
93 FT_CALLBACK_DEF( void )
94 pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */
96 PCF_CMap pcfcmap = (PCF_CMap)cmap;
103 FT_CALLBACK_DEF( FT_UInt )
104 pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */
107 PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
109 FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
110 FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
111 FT_UInt32 h = enc->lastRow - enc->firstRow + 1;
112 FT_UInt32 w = enc->lastCol - enc->firstCol + 1;
115 /* wrapped around "negative" values are also rejected */
116 if ( i >= h || j >= w )
119 return (FT_UInt)enc->offset[i * w + j];
123 FT_CALLBACK_DEF( FT_UInt )
124 pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */
125 FT_UInt32 *acharcode )
127 PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
128 FT_UInt32 charcode = *acharcode + 1;
130 FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
131 FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
132 FT_UInt32 h = enc->lastRow - enc->firstRow + 1;
133 FT_UInt32 w = enc->lastCol - enc->firstCol + 1;
138 /* adjust wrapped around "negative" values */
139 if ( (FT_Int32)i < 0 )
141 if ( (FT_Int32)j < 0 )
144 for ( ; i < h; i++, j = 0 )
147 result = (FT_UInt)enc->offset[i * w + j];
148 if ( result != 0xFFFFU )
153 *acharcode = ( ( i + enc->firstRow ) << 8 ) | ( j + enc->firstCol );
160 const FT_CMap_ClassRec pcf_cmap_class =
162 sizeof ( PCF_CMapRec ),
168 NULL, NULL, NULL, NULL, NULL
172 FT_CALLBACK_DEF( void )
173 PCF_Face_Done( FT_Face face ) /* PCF_Face */
175 PCF_Face pcfface = (PCF_Face)face;
182 memory = FT_FACE_MEMORY( face );
184 FT_FREE( pcfface->metrics );
185 FT_FREE( pcfface->enc.offset );
187 /* free properties */
188 if ( pcfface->properties )
193 for ( i = 0; i < pcfface->nprops; i++ )
195 PCF_Property prop = &pcfface->properties[i];
200 FT_FREE( prop->name );
201 if ( prop->isString )
202 FT_FREE( prop->value.atom );
206 FT_FREE( pcfface->properties );
209 FT_FREE( pcfface->toc.tables );
210 FT_FREE( face->family_name );
211 FT_FREE( face->style_name );
212 FT_FREE( face->available_sizes );
213 FT_FREE( pcfface->charset_encoding );
214 FT_FREE( pcfface->charset_registry );
216 /* close compressed stream if any */
217 if ( face->stream == &pcfface->comp_stream )
219 FT_Stream_Close( &pcfface->comp_stream );
220 face->stream = pcfface->comp_source;
225 FT_CALLBACK_DEF( FT_Error )
226 PCF_Face_Init( FT_Stream stream,
227 FT_Face face, /* PCF_Face */
230 FT_Parameter* params )
232 PCF_Face pcfface = (PCF_Face)face;
235 FT_UNUSED( num_params );
239 FT_TRACE2(( "PCF driver\n" ));
241 error = pcf_load_font( stream, pcfface, face_index );
244 PCF_Face_Done( face );
246 #if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \
247 defined( FT_CONFIG_OPTION_USE_LZW ) || \
248 defined( FT_CONFIG_OPTION_USE_BZIP2 )
250 #ifdef FT_CONFIG_OPTION_USE_ZLIB
255 /* this didn't work, try gzip support! */
256 FT_TRACE2(( " ... try gzip stream\n" ));
257 error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream );
258 if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
263 #endif /* FT_CONFIG_OPTION_USE_ZLIB */
265 #ifdef FT_CONFIG_OPTION_USE_LZW
271 /* this didn't work, try LZW support! */
272 FT_TRACE2(( " ... try LZW stream\n" ));
273 error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream );
274 if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
279 #endif /* FT_CONFIG_OPTION_USE_LZW */
281 #ifdef FT_CONFIG_OPTION_USE_BZIP2
287 /* this didn't work, try Bzip2 support! */
288 FT_TRACE2(( " ... try Bzip2 stream\n" ));
289 error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream );
290 if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
295 #endif /* FT_CONFIG_OPTION_USE_BZIP2 */
300 pcfface->comp_source = stream;
301 face->stream = &pcfface->comp_stream;
303 stream = face->stream;
305 error = pcf_load_font( stream, pcfface, face_index );
309 #else /* !(FT_CONFIG_OPTION_USE_ZLIB ||
310 FT_CONFIG_OPTION_USE_LZW ||
311 FT_CONFIG_OPTION_USE_BZIP2) */
318 /* PCF cannot have multiple faces in a single font file.
319 * XXX: A non-zero face_index is already an invalid argument, but
320 * Type1, Type42 drivers have a convention to return
321 * an invalid argument error when the font could be
322 * opened by the specified driver.
324 if ( face_index < 0 )
326 else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
328 FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
329 PCF_Face_Done( face );
330 return FT_THROW( Invalid_Argument );
335 FT_String *charset_registry = pcfface->charset_registry;
336 FT_String *charset_encoding = pcfface->charset_encoding;
337 FT_Bool unicode_charmap = 0;
340 if ( charset_registry && charset_encoding )
342 char* s = charset_registry;
345 /* Uh, oh, compare first letters manually to avoid dependency
347 if ( ( s[0] == 'i' || s[0] == 'I' ) &&
348 ( s[1] == 's' || s[1] == 'S' ) &&
349 ( s[2] == 'o' || s[2] == 'O' ) )
352 if ( !ft_strcmp( s, "10646" ) ||
353 ( !ft_strcmp( s, "8859" ) &&
354 !ft_strcmp( pcfface->charset_encoding, "1" ) ) )
356 /* another name for ASCII */
357 else if ( !ft_strcmp( s, "646.1991" ) &&
358 !ft_strcmp( pcfface->charset_encoding, "IRV" ) )
364 FT_CharMapRec charmap;
368 charmap.encoding = FT_ENCODING_NONE;
369 /* initial platform/encoding should indicate unset status? */
370 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
371 charmap.encoding_id = TT_APPLE_ID_DEFAULT;
373 if ( unicode_charmap )
375 charmap.encoding = FT_ENCODING_UNICODE;
376 charmap.platform_id = TT_PLATFORM_MICROSOFT;
377 charmap.encoding_id = TT_MS_ID_UNICODE_CS;
380 error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
388 FT_TRACE2(( " not a PCF file\n" ));
389 PCF_Face_Done( face );
390 error = FT_THROW( Unknown_File_Format ); /* error */
395 FT_CALLBACK_DEF( FT_Error )
396 PCF_Size_Select( FT_Size size,
397 FT_ULong strike_index )
399 PCF_Accel accel = &( (PCF_Face)size->face )->accel;
402 FT_Select_Metrics( size->face, strike_index );
404 size->metrics.ascender = accel->fontAscent * 64;
405 size->metrics.descender = -accel->fontDescent * 64;
406 size->metrics.max_advance = accel->maxbounds.characterWidth * 64;
412 FT_CALLBACK_DEF( FT_Error )
413 PCF_Size_Request( FT_Size size,
414 FT_Size_Request req )
416 PCF_Face face = (PCF_Face)size->face;
417 FT_Bitmap_Size* bsize = size->face->available_sizes;
418 FT_Error error = FT_ERR( Invalid_Pixel_Size );
422 height = FT_REQUEST_HEIGHT( req );
423 height = ( height + 32 ) >> 6;
427 case FT_SIZE_REQUEST_TYPE_NOMINAL:
428 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
432 case FT_SIZE_REQUEST_TYPE_REAL_DIM:
433 if ( height == ( face->accel.fontAscent +
434 face->accel.fontDescent ) )
439 error = FT_THROW( Unimplemented_Feature );
446 return PCF_Size_Select( size, 0 );
450 FT_CALLBACK_DEF( FT_Error )
451 PCF_Glyph_Load( FT_GlyphSlot slot,
454 FT_Int32 load_flags )
456 PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
458 FT_Error error = FT_Err_Ok;
459 FT_Bitmap* bitmap = &slot->bitmap;
464 FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index ));
468 error = FT_THROW( Invalid_Face_Handle );
472 if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
474 error = FT_THROW( Invalid_Argument );
478 stream = face->root.stream;
480 metric = face->metrics + glyph_index;
482 bitmap->rows = (unsigned int)( metric->ascent +
484 bitmap->width = (unsigned int)( metric->rightSideBearing -
485 metric->leftSideBearing );
486 bitmap->num_grays = 1;
487 bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
489 switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
492 bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 );
496 bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 );
500 bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 );
504 bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 );
508 return FT_THROW( Invalid_File_Format );
511 slot->format = FT_GLYPH_FORMAT_BITMAP;
512 slot->bitmap_left = metric->leftSideBearing;
513 slot->bitmap_top = metric->ascent;
515 slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 );
516 slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
517 slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
518 slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing -
519 metric->leftSideBearing ) * 64 );
520 slot->metrics.height = (FT_Pos)( bitmap->rows * 64 );
522 ft_synthesize_vertical_metrics( &slot->metrics,
523 ( face->accel.fontAscent +
524 face->accel.fontDescent ) * 64 );
526 if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
529 /* XXX: to do: are there cases that need repadding the bitmap? */
530 bytes = (FT_ULong)bitmap->pitch * bitmap->rows;
532 error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes );
536 if ( FT_STREAM_SEEK( metric->bits ) ||
537 FT_STREAM_READ( bitmap->buffer, bytes ) )
540 if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
541 BitOrderInvert( bitmap->buffer, bytes );
543 if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
544 PCF_BIT_ORDER( face->bitmapsFormat ) ) )
546 switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
552 TwoByteSwap( bitmap->buffer, bytes );
556 FourByteSwap( bitmap->buffer, bytes );
572 FT_CALLBACK_DEF( FT_Error )
573 pcf_get_bdf_property( FT_Face face, /* PCF_Face */
574 const char* prop_name,
575 BDF_PropertyRec *aproperty )
577 PCF_Face pcfface = (PCF_Face)face;
581 prop = pcf_find_property( pcfface, prop_name );
584 if ( prop->isString )
586 aproperty->type = BDF_PROPERTY_TYPE_ATOM;
587 aproperty->u.atom = prop->value.atom;
591 if ( prop->value.l > 0x7FFFFFFFL ||
592 prop->value.l < ( -1 - 0x7FFFFFFFL ) )
594 FT_TRACE2(( "pcf_get_bdf_property:"
595 " too large integer 0x%lx is truncated\n",
600 * The PCF driver loads all properties as signed integers.
601 * This really doesn't seem to be a problem, because this is
602 * sufficient for any meaningful values.
604 aproperty->type = BDF_PROPERTY_TYPE_INTEGER;
605 aproperty->u.integer = (FT_Int32)prop->value.l;
611 return FT_THROW( Invalid_Argument );
615 FT_CALLBACK_DEF( FT_Error )
616 pcf_get_charset_id( FT_Face face, /* PCF_Face */
617 const char* *acharset_encoding,
618 const char* *acharset_registry )
620 PCF_Face pcfface = (PCF_Face)face;
623 *acharset_encoding = pcfface->charset_encoding;
624 *acharset_registry = pcfface->charset_registry;
630 static const FT_Service_BDFRec pcf_service_bdf =
632 (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, /* get_charset_id */
633 (FT_BDF_GetPropertyFunc) pcf_get_bdf_property /* get_property */
641 FT_CALLBACK_DEF( FT_Error )
642 pcf_property_set( FT_Module module, /* PCF_Driver */
643 const char* property_name,
645 FT_Bool value_is_string )
647 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
649 FT_Error error = FT_Err_Ok;
650 PCF_Driver driver = (PCF_Driver)module;
652 #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
653 FT_UNUSED( value_is_string );
657 if ( !ft_strcmp( property_name, "no-long-family-names" ) )
659 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
660 if ( value_is_string )
662 const char* s = (const char*)value;
663 long lfn = ft_strtol( s, NULL, 10 );
667 driver->no_long_family_names = 0;
669 driver->no_long_family_names = 1;
671 return FT_THROW( Invalid_Argument );
676 FT_Bool* no_long_family_names = (FT_Bool*)value;
679 driver->no_long_family_names = *no_long_family_names;
685 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
689 FT_UNUSED( value_is_string );
690 #ifndef FT_DEBUG_LEVEL_TRACE
691 FT_UNUSED( property_name );
694 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
696 FT_TRACE2(( "pcf_property_set: missing property `%s'\n",
698 return FT_THROW( Missing_Property );
702 FT_CALLBACK_DEF( FT_Error )
703 pcf_property_get( FT_Module module, /* PCF_Driver */
704 const char* property_name,
707 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
709 FT_Error error = FT_Err_Ok;
710 PCF_Driver driver = (PCF_Driver)module;
713 if ( !ft_strcmp( property_name, "no-long-family-names" ) )
715 FT_Bool no_long_family_names = driver->no_long_family_names;
716 FT_Bool* val = (FT_Bool*)value;
719 *val = no_long_family_names;
724 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
728 #ifndef FT_DEBUG_LEVEL_TRACE
729 FT_UNUSED( property_name );
732 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
734 FT_TRACE2(( "pcf_property_get: missing property `%s'\n",
736 return FT_THROW( Missing_Property );
740 FT_DEFINE_SERVICE_PROPERTIESREC(
741 pcf_service_properties,
743 (FT_Properties_SetFunc)pcf_property_set, /* set_property */
744 (FT_Properties_GetFunc)pcf_property_get ) /* get_property */
753 static const FT_ServiceDescRec pcf_services[] =
755 { FT_SERVICE_ID_BDF, &pcf_service_bdf },
756 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF },
757 { FT_SERVICE_ID_PROPERTIES, &pcf_service_properties },
762 FT_CALLBACK_DEF( FT_Module_Interface )
763 pcf_driver_requester( FT_Module module,
768 return ft_service_list_lookup( pcf_services, name );
772 FT_CALLBACK_DEF( FT_Error )
773 pcf_driver_init( FT_Module module ) /* PCF_Driver */
775 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
776 PCF_Driver driver = (PCF_Driver)module;
779 driver->no_long_family_names = 0;
788 FT_CALLBACK_DEF( void )
789 pcf_driver_done( FT_Module module ) /* PCF_Driver */
795 FT_CALLBACK_TABLE_DEF
796 const FT_Driver_ClassRec pcf_driver_class =
799 FT_MODULE_FONT_DRIVER |
800 FT_MODULE_DRIVER_NO_OUTLINES,
802 sizeof ( PCF_DriverRec ),
807 NULL, /* module-specific interface */
809 pcf_driver_init, /* FT_Module_Constructor module_init */
810 pcf_driver_done, /* FT_Module_Destructor module_done */
811 pcf_driver_requester /* FT_Module_Requester get_interface */
814 sizeof ( PCF_FaceRec ),
815 sizeof ( FT_SizeRec ),
816 sizeof ( FT_GlyphSlotRec ),
818 PCF_Face_Init, /* FT_Face_InitFunc init_face */
819 PCF_Face_Done, /* FT_Face_DoneFunc done_face */
820 NULL, /* FT_Size_InitFunc init_size */
821 NULL, /* FT_Size_DoneFunc done_size */
822 NULL, /* FT_Slot_InitFunc init_slot */
823 NULL, /* FT_Slot_DoneFunc done_slot */
825 PCF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */
827 NULL, /* FT_Face_GetKerningFunc get_kerning */
828 NULL, /* FT_Face_AttachFunc attach_file */
829 NULL, /* FT_Face_GetAdvancesFunc get_advances */
831 PCF_Size_Request, /* FT_Size_RequestFunc request_size */
832 PCF_Size_Select /* FT_Size_SelectFunc select_size */