1 /***************************************************************************/ 2 /* */ 3 /* pfrobjs.c */ 4 /* */ 5 /* FreeType PFR object methods (body). */ 6 /* */ 7 /* Copyright 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include "pfrobjs.h" 20 #include "pfrload.h" 21 #include "pfrgload.h" 22 #include "pfrcmap.h" 23 #include "pfrsbit.h" 24 #include FT_OUTLINE_H 25 #include FT_INTERNAL_DEBUG_H 26 27 #include "pfrerror.h" 28 29 #undef FT_COMPONENT 30 #define FT_COMPONENT trace_pfr 31 32 33 /*************************************************************************/ 34 /*************************************************************************/ 35 /***** *****/ 36 /***** FACE OBJECT METHODS *****/ 37 /***** *****/ 38 /*************************************************************************/ 39 /*************************************************************************/ 40 41 FT_LOCAL_DEF( void ) pfr_face_done(PFR_Face face)42 pfr_face_done( PFR_Face face ) 43 { 44 /* finalize the physical font record */ 45 pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) ); 46 47 /* no need to finalize the logical font or the header */ 48 } 49 50 51 FT_LOCAL_DEF( FT_Error ) pfr_face_init(FT_Stream stream,PFR_Face face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)52 pfr_face_init( FT_Stream stream, 53 PFR_Face face, 54 FT_Int face_index, 55 FT_Int num_params, 56 FT_Parameter* params ) 57 { 58 FT_Error error; 59 60 FT_UNUSED( num_params ); 61 FT_UNUSED( params ); 62 63 64 /* load the header and check it */ 65 error = pfr_header_load( &face->header, stream ); 66 if ( error ) 67 goto Exit; 68 69 if ( !pfr_header_check( &face->header ) ) 70 { 71 FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" )); 72 error = PFR_Err_Unknown_File_Format; 73 goto Exit; 74 } 75 76 /* check face index */ 77 { 78 FT_UInt num_faces; 79 80 81 error = pfr_log_font_count( stream, 82 face->header.log_dir_offset, 83 &num_faces ); 84 if ( error ) 85 goto Exit; 86 87 face->root.num_faces = num_faces; 88 } 89 90 if ( face_index < 0 ) 91 goto Exit; 92 93 if ( face_index >= face->root.num_faces ) 94 { 95 FT_ERROR(( "pfr_face_init: invalid face index\n" )); 96 error = PFR_Err_Invalid_Argument; 97 goto Exit; 98 } 99 100 /* load the face */ 101 error = pfr_log_font_load( 102 &face->log_font, stream, face_index, 103 face->header.log_dir_offset, 104 FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); 105 if ( error ) 106 goto Exit; 107 108 /* now load the physical font descriptor */ 109 error = pfr_phy_font_load( &face->phy_font, stream, 110 face->log_font.phys_offset, 111 face->log_font.phys_size ); 112 if ( error ) 113 goto Exit; 114 115 /* now, set-up all root face fields */ 116 { 117 FT_Face root = FT_FACE( face ); 118 PFR_PhyFont phy_font = &face->phy_font; 119 120 121 root->face_index = face_index; 122 root->num_glyphs = phy_font->num_chars; 123 root->face_flags = FT_FACE_FLAG_SCALABLE; 124 125 if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 ) 126 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 127 128 if ( phy_font->flags & PFR_PHY_VERTICAL ) 129 root->face_flags |= FT_FACE_FLAG_VERTICAL; 130 else 131 root->face_flags |= FT_FACE_FLAG_HORIZONTAL; 132 133 if ( phy_font->num_strikes > 0 ) 134 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; 135 136 if ( phy_font->num_kern_pairs > 0 ) 137 root->face_flags |= FT_FACE_FLAG_KERNING; 138 139 root->family_name = phy_font->font_id; 140 root->style_name = NULL; /* no style name in font file */ 141 142 root->num_fixed_sizes = 0; 143 root->available_sizes = 0; 144 145 root->bbox = phy_font->bbox; 146 root->units_per_EM = (FT_UShort)phy_font->outline_resolution; 147 root->ascender = (FT_Short) phy_font->bbox.yMax; 148 root->descender = (FT_Short) phy_font->bbox.yMin; 149 root->height = (FT_Short) 150 ( ( ( root->ascender - root->descender ) * 12 ) 151 / 10 ); 152 153 /* now compute maximum advance width */ 154 if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) 155 root->max_advance_width = (FT_Short)phy_font->standard_advance; 156 else 157 { 158 FT_Int max = 0; 159 FT_UInt count = phy_font->num_chars; 160 PFR_Char gchar = phy_font->chars; 161 162 163 for ( ; count > 0; count--, gchar++ ) 164 { 165 if ( max < gchar->advance ) 166 max = gchar->advance; 167 } 168 169 root->max_advance_width = (FT_Short)max; 170 } 171 172 root->max_advance_height = root->height; 173 174 root->underline_position = (FT_Short)( - root->units_per_EM / 10 ); 175 root->underline_thickness = (FT_Short)( root->units_per_EM / 30 ); 176 177 /* create charmap */ 178 { 179 FT_CharMapRec charmap; 180 181 182 charmap.face = root; 183 charmap.platform_id = 3; 184 charmap.encoding_id = 1; 185 charmap.encoding = FT_ENCODING_UNICODE; 186 187 FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); 188 189 #if 0 190 /* Select default charmap */ 191 if (root->num_charmaps) 192 root->charmap = root->charmaps[0]; 193 #endif 194 } 195 196 /* check whether we've loaded any kerning pairs */ 197 if ( phy_font->num_kern_pairs ) 198 root->face_flags |= FT_FACE_FLAG_KERNING; 199 } 200 201 Exit: 202 return error; 203 } 204 205 206 /*************************************************************************/ 207 /*************************************************************************/ 208 /***** *****/ 209 /***** SLOT OBJECT METHOD *****/ 210 /***** *****/ 211 /*************************************************************************/ 212 /*************************************************************************/ 213 214 FT_LOCAL_DEF( FT_Error ) pfr_slot_init(PFR_Slot slot)215 pfr_slot_init( PFR_Slot slot ) 216 { 217 FT_GlyphLoader loader = slot->root.internal->loader; 218 219 pfr_glyph_init( &slot->glyph, loader ); 220 221 return 0; 222 } 223 224 225 FT_LOCAL_DEF( void ) pfr_slot_done(PFR_Slot slot)226 pfr_slot_done( PFR_Slot slot ) 227 { 228 pfr_glyph_done( &slot->glyph ); 229 } 230 231 232 FT_LOCAL_DEF( FT_Error ) pfr_slot_load(PFR_Slot slot,PFR_Size size,FT_UInt gindex,FT_Int32 load_flags)233 pfr_slot_load( PFR_Slot slot, 234 PFR_Size size, 235 FT_UInt gindex, 236 FT_Int32 load_flags ) 237 { 238 FT_Error error; 239 PFR_Face face = (PFR_Face)slot->root.face; 240 PFR_Char gchar; 241 FT_Outline* outline = &slot->root.outline; 242 FT_ULong gps_offset; 243 244 if (gindex > 0) 245 gindex--; 246 247 /* check that the glyph index is correct */ 248 FT_ASSERT( gindex < face->phy_font.num_chars ); 249 250 /* try to load an embedded bitmap */ 251 if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) 252 { 253 error = pfr_slot_load_bitmap( slot, size, gindex ); 254 if ( error == 0 ) 255 goto Exit; 256 } 257 258 gchar = face->phy_font.chars + gindex; 259 slot->root.format = FT_GLYPH_FORMAT_OUTLINE; 260 outline->n_points = 0; 261 outline->n_contours = 0; 262 gps_offset = face->header.gps_section_offset; 263 264 /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ 265 error = pfr_glyph_load( &slot->glyph, face->root.stream, 266 gps_offset, gchar->gps_offset, gchar->gps_size ); 267 268 if ( !error ) 269 { 270 FT_BBox cbox; 271 FT_Glyph_Metrics* metrics = &slot->root.metrics; 272 FT_Pos advance; 273 FT_Int em_metrics, em_outline; 274 FT_Bool scaling; 275 276 277 scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); 278 279 /* copy outline data */ 280 *outline = slot->glyph.loader->base.outline; 281 282 outline->flags &= ~FT_OUTLINE_OWNER; 283 outline->flags |= FT_OUTLINE_REVERSE_FILL; 284 285 if ( size && size->root.metrics.y_ppem < 24 ) 286 outline->flags |= FT_OUTLINE_HIGH_PRECISION; 287 288 /* compute the advance vector */ 289 metrics->horiAdvance = 0; 290 metrics->vertAdvance = 0; 291 292 advance = gchar->advance; 293 em_metrics = face->phy_font.metrics_resolution; 294 em_outline = face->phy_font.outline_resolution; 295 296 if ( em_metrics != em_outline ) 297 advance = FT_MulDiv( advance, em_outline, em_metrics ); 298 299 if ( face->phy_font.flags & PFR_PHY_VERTICAL ) 300 metrics->vertAdvance = advance; 301 else 302 metrics->horiAdvance = advance; 303 304 slot->root.linearHoriAdvance = metrics->horiAdvance; 305 slot->root.linearVertAdvance = metrics->vertAdvance; 306 307 /* make-up vertical metrics(?) */ 308 metrics->vertBearingX = 0; 309 metrics->vertBearingY = 0; 310 311 /* scale when needed */ 312 if ( scaling ) 313 { 314 FT_Int n; 315 FT_Fixed x_scale = size->root.metrics.x_scale; 316 FT_Fixed y_scale = size->root.metrics.y_scale; 317 FT_Vector* vec = outline->points; 318 319 320 /* scale outline points */ 321 for ( n = 0; n < outline->n_points; n++, vec++ ) 322 { 323 vec->x = FT_MulFix( vec->x, x_scale ); 324 vec->y = FT_MulFix( vec->y, y_scale ); 325 } 326 327 /* scale the advance */ 328 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); 329 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); 330 } 331 332 /* compute the rest of the metrics */ 333 FT_Outline_Get_CBox( outline, &cbox ); 334 335 metrics->width = cbox.xMax - cbox.xMin; 336 metrics->height = cbox.yMax - cbox.yMin; 337 metrics->horiBearingX = cbox.xMin; 338 metrics->horiBearingY = cbox.yMax - metrics->height; 339 } 340 341 Exit: 342 return error; 343 } 344 345 346 /*************************************************************************/ 347 /*************************************************************************/ 348 /***** *****/ 349 /***** KERNING METHOD *****/ 350 /***** *****/ 351 /*************************************************************************/ 352 /*************************************************************************/ 353 354 FT_LOCAL_DEF( FT_Error ) pfr_face_get_kerning(PFR_Face face,FT_UInt glyph1,FT_UInt glyph2,FT_Vector * kerning)355 pfr_face_get_kerning( PFR_Face face, 356 FT_UInt glyph1, 357 FT_UInt glyph2, 358 FT_Vector* kerning ) 359 { 360 FT_Error error; 361 PFR_PhyFont phy_font = &face->phy_font; 362 PFR_KernItem item = phy_font->kern_items; 363 FT_UInt32 idx = PFR_KERN_INDEX( glyph1, glyph2 ); 364 365 366 kerning->x = 0; 367 kerning->y = 0; 368 369 /* find the kerning item containing our pair */ 370 while ( item ) 371 { 372 if ( item->pair1 <= idx && idx <= item->pair2 ) 373 goto Found_Item; 374 375 item = item->next; 376 } 377 378 /* not found */ 379 goto Exit; 380 381 Found_Item: 382 { 383 /* perform simply binary search within the item */ 384 FT_UInt min, mid, max; 385 FT_Stream stream = face->root.stream; 386 FT_Byte* p; 387 388 389 if ( FT_STREAM_SEEK( item->offset ) || 390 FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) 391 goto Exit; 392 393 min = 0; 394 max = item->pair_count; 395 while ( min < max ) 396 { 397 FT_UInt char1, char2, charcode; 398 399 400 mid = ( min + max ) >> 1; 401 p = stream->cursor + mid*item->pair_size; 402 403 if ( item->flags & PFR_KERN_2BYTE_CHAR ) 404 { 405 char1 = FT_NEXT_USHORT( p ); 406 char2 = FT_NEXT_USHORT( p ); 407 } 408 else 409 { 410 char1 = FT_NEXT_USHORT( p ); 411 char2 = FT_NEXT_USHORT( p ); 412 } 413 charcode = PFR_KERN_INDEX( char1, char2 ); 414 415 if ( idx == charcode ) 416 { 417 if ( item->flags & PFR_KERN_2BYTE_ADJ ) 418 kerning->x = item->base_adj + FT_NEXT_SHORT( p ); 419 else 420 kerning->x = item->base_adj + FT_NEXT_CHAR( p ); 421 422 break; 423 } 424 if ( idx > charcode ) 425 min = mid + 1; 426 else 427 max = mid; 428 } 429 430 FT_FRAME_EXIT(); 431 } 432 433 Exit: 434 return 0; 435 } 436 437 /* END */ 438