update for HEAD-2003050101
[reactos.git] / lib / freetype / src / pfr / pfrobjs.c
diff --git a/lib/freetype/src/pfr/pfrobjs.c b/lib/freetype/src/pfr/pfrobjs.c
new file mode 100644 (file)
index 0000000..867644a
--- /dev/null
@@ -0,0 +1,481 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrobjs.c                                                              */
+/*                                                                         */
+/*    FreeType PFR object methods (body).                                  */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrobjs.h"
+#include "pfrload.h"
+#include "pfrgload.h"
+#include "pfrcmap.h"
+#include "pfrsbit.h"
+#include FT_OUTLINE_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pfr
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     FACE OBJECT METHODS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  pfr_face_done( PFR_Face  face )
+  {
+    FT_Memory   memory = face->root.driver->root.memory;
+
+    /* we don't want dangling pointers */
+    face->root.family_name = NULL;
+    face->root.style_name  = NULL;
+    
+    /* finalize the physical font record */
+    pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
+
+    /* no need to finalize the logical font or the header */
+    FT_FREE( face->root.available_sizes );
+  }
+
+
+  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 )
+  {
+    FT_Error  error;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+
+
+    /* load the header and check it */
+    error = pfr_header_load( &face->header, stream );
+    if ( error )
+      goto Exit;
+
+    if ( !pfr_header_check( &face->header ) )
+    {
+      FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
+      error = PFR_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* check face index */
+    {
+      FT_UInt  num_faces;
+
+
+      error = pfr_log_font_count( stream,
+                                  face->header.log_dir_offset,
+                                  &num_faces );
+      if ( error )
+        goto Exit;
+
+      face->root.num_faces = num_faces;
+    }
+
+    if ( face_index < 0 )
+      goto Exit;
+
+    if ( face_index >= face->root.num_faces )
+    {
+      FT_ERROR(( "pfr_face_init: invalid face index\n" ));
+      error = PFR_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* load the face */
+    error = pfr_log_font_load(
+               &face->log_font, stream, face_index,
+               face->header.log_dir_offset,
+               FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
+    if ( error )
+      goto Exit;
+
+    /* now load the physical font descriptor */
+     error = pfr_phy_font_load( &face->phy_font, stream,
+                                 face->log_font.phys_offset,
+                                 face->log_font.phys_size );
+     if ( error )
+       goto Exit;
+
+     /* now, set-up all root face fields */
+     {
+       FT_Face      root     = FT_FACE( face );
+       PFR_PhyFont  phy_font = &face->phy_font;
+
+
+       root->face_index = face_index;
+       root->num_glyphs = phy_font->num_chars;
+       root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+       if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
+         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+       if ( phy_font->flags & PFR_PHY_VERTICAL )
+         root->face_flags |= FT_FACE_FLAG_VERTICAL;
+       else
+         root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+       if ( phy_font->num_strikes > 0 )
+         root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+       if ( phy_font->num_kern_pairs > 0 )
+         root->face_flags |= FT_FACE_FLAG_KERNING;
+
+      /* if no family name was found in the "undocumented" auxiliary
+       * data, use the font ID instead. This sucks but is better than
+       * nothing
+       */
+       root->family_name = phy_font->family_name;
+       if ( root->family_name == NULL )
+         root->family_name = phy_font->font_id;
+
+      /* note that the style name can be NULL in certain PFR fonts,
+       * probably meaning "Regular"
+       */
+       root->style_name  = phy_font->style_name;
+
+       root->num_fixed_sizes = 0;
+       root->available_sizes = 0;
+
+       root->bbox         = phy_font->bbox;
+       root->units_per_EM = (FT_UShort)phy_font->outline_resolution;
+       root->ascender     = (FT_Short) phy_font->bbox.yMax;
+       root->descender    = (FT_Short) phy_font->bbox.yMin;
+       root->height       = (FT_Short)
+                              ( ( ( root->ascender - root->descender ) * 12 )
+                                / 10 );
+
+       if ( phy_font->num_strikes > 0 )
+       {
+         FT_UInt          n, count = phy_font->num_strikes;
+         FT_Bitmap_Size*  size;
+         PFR_Strike       strike;
+         FT_Memory        memory = root->stream->memory;
+         
+         
+         if ( FT_NEW_ARRAY( root->available_sizes, count ) )
+           goto Exit;
+         
+         size   = root->available_sizes;
+         strike = phy_font->strikes;
+         for ( n = 0; n < count; n++, size++, strike++ )
+         {
+           size->height = (FT_UShort) strike->y_ppm;
+           size->width  = (FT_UShort) strike->x_ppm;
+         }
+         root->num_fixed_sizes = count;
+       }
+
+       /* now compute maximum advance width */
+       if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
+         root->max_advance_width = (FT_Short)phy_font->standard_advance;
+       else
+       {
+         FT_Int    max = 0;
+         FT_UInt   count = phy_font->num_chars;
+         PFR_Char  gchar = phy_font->chars;
+
+
+         for ( ; count > 0; count--, gchar++ )
+         {
+           if ( max < gchar->advance )
+             max = gchar->advance;
+         }
+
+         root->max_advance_width = (FT_Short)max;
+       }
+
+       root->max_advance_height = root->height;
+
+       root->underline_position  = (FT_Short)( - root->units_per_EM / 10 );
+       root->underline_thickness = (FT_Short)(   root->units_per_EM / 30 );
+
+       /* create charmap */
+       {
+         FT_CharMapRec  charmap;
+
+
+         charmap.face        = root;
+         charmap.platform_id = 3;
+         charmap.encoding_id = 1;
+         charmap.encoding    = FT_ENCODING_UNICODE;
+
+         FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
+
+#if 0
+         /* Select default charmap */
+         if (root->num_charmaps)
+           root->charmap = root->charmaps[0];
+#endif
+       }
+
+       /* check whether we've loaded any kerning pairs */
+       if ( phy_font->num_kern_pairs )
+         root->face_flags |= FT_FACE_FLAG_KERNING;
+     }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    SLOT OBJECT METHOD                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_slot_init( PFR_Slot  slot )
+  {
+    FT_GlyphLoader  loader = slot->root.internal->loader;
+
+    pfr_glyph_init( &slot->glyph, loader );
+
+    return 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  pfr_slot_done( PFR_Slot  slot )
+  {
+    pfr_glyph_done( &slot->glyph );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_slot_load( PFR_Slot  slot,
+                 PFR_Size  size,
+                 FT_UInt   gindex,
+                 FT_Int32  load_flags )
+  {
+    FT_Error     error;
+    PFR_Face     face    = (PFR_Face)slot->root.face;
+    PFR_Char     gchar;
+    FT_Outline*  outline = &slot->root.outline;
+    FT_ULong     gps_offset;
+
+    if (gindex > 0)
+      gindex--;
+
+    /* check that the glyph index is correct */
+    FT_ASSERT( gindex < face->phy_font.num_chars );
+
+    /* try to load an embedded bitmap */
+    if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
+    {
+      error = pfr_slot_load_bitmap( slot, size, gindex );
+      if ( error == 0 )
+        goto Exit;
+    }
+
+    if ( load_flags & FT_LOAD_SBITS_ONLY )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    gchar               = face->phy_font.chars + gindex;
+    slot->root.format   = FT_GLYPH_FORMAT_OUTLINE;
+    outline->n_points   = 0;
+    outline->n_contours = 0;
+    gps_offset          = face->header.gps_section_offset;
+
+    /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
+    error = pfr_glyph_load( &slot->glyph, face->root.stream,
+                            gps_offset, gchar->gps_offset, gchar->gps_size );
+
+    if ( !error )
+    {
+      FT_BBox            cbox;
+      FT_Glyph_Metrics*  metrics = &slot->root.metrics;
+      FT_Pos             advance;
+      FT_Int             em_metrics, em_outline;
+      FT_Bool            scaling;
+
+
+      scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
+
+      /* copy outline data */
+      *outline = slot->glyph.loader->base.outline;
+
+      outline->flags &= ~FT_OUTLINE_OWNER;
+      outline->flags |= FT_OUTLINE_REVERSE_FILL;
+
+      if ( size && size->root.metrics.y_ppem < 24 )
+        outline->flags |= FT_OUTLINE_HIGH_PRECISION;
+
+      /* compute the advance vector */
+      metrics->horiAdvance = 0;
+      metrics->vertAdvance = 0;
+
+      advance    = gchar->advance;
+      em_metrics = face->phy_font.metrics_resolution;
+      em_outline = face->phy_font.outline_resolution;
+
+      if ( em_metrics != em_outline )
+        advance = FT_MulDiv( advance, em_outline, em_metrics );
+
+      if ( face->phy_font.flags & PFR_PHY_VERTICAL )
+        metrics->vertAdvance = advance;
+      else
+        metrics->horiAdvance = advance;
+
+      slot->root.linearHoriAdvance = metrics->horiAdvance;
+      slot->root.linearVertAdvance = metrics->vertAdvance;
+
+      /* make-up vertical metrics(?) */
+      metrics->vertBearingX = 0;
+      metrics->vertBearingY = 0;
+
+      /* scale when needed */
+      if ( scaling )
+      {
+        FT_Int      n;
+        FT_Fixed    x_scale = size->root.metrics.x_scale;
+        FT_Fixed    y_scale = size->root.metrics.y_scale;
+        FT_Vector*  vec     = outline->points;
+
+
+        /* scale outline points */
+        for ( n = 0; n < outline->n_points; n++, vec++ )
+        {
+          vec->x = FT_MulFix( vec->x, x_scale );
+          vec->y = FT_MulFix( vec->y, y_scale );
+        }
+
+        /* scale the advance */
+        metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+        metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+      }
+
+      /* compute the rest of the metrics */
+      FT_Outline_Get_CBox( outline, &cbox );
+
+      metrics->width        = cbox.xMax - cbox.xMin;
+      metrics->height       = cbox.yMax - cbox.yMin;
+      metrics->horiBearingX = cbox.xMin;
+      metrics->horiBearingY = cbox.yMax - metrics->height;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      KERNING METHOD                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_face_get_kerning( PFR_Face    face,
+                        FT_UInt     glyph1,
+                        FT_UInt     glyph2,
+                        FT_Vector*  kerning )
+  {
+    FT_Error      error;
+    PFR_PhyFont   phy_font = &face->phy_font;
+    PFR_KernItem  item     = phy_font->kern_items;
+    FT_UInt32     idx      = PFR_KERN_INDEX( glyph1, glyph2 );
+
+
+    kerning->x = 0;
+    kerning->y = 0;
+
+    /* find the kerning item containing our pair */
+    while ( item )
+    {
+      if ( item->pair1 <= idx && idx <= item->pair2 )
+        goto Found_Item;
+
+      item = item->next;
+    }
+
+    /* not found */
+    goto Exit;
+
+  Found_Item:
+    {
+      /* perform simply binary search within the item */
+      FT_UInt    min, mid, max;
+      FT_Stream  stream = face->root.stream;
+      FT_Byte*   p;
+
+
+      if ( FT_STREAM_SEEK( item->offset )                       ||
+           FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
+        goto Exit;
+
+      min = 0;
+      max = item->pair_count;
+      while ( min < max )
+      {
+        FT_UInt  char1, char2, charcode;
+
+
+        mid = ( min + max ) >> 1;
+        p   = stream->cursor + mid*item->pair_size;
+
+        if ( item->flags & PFR_KERN_2BYTE_CHAR )
+        {
+          char1 = FT_NEXT_USHORT( p );
+          char2 = FT_NEXT_USHORT( p );
+        }
+        else
+        {
+          char1 = FT_NEXT_USHORT( p );
+          char2 = FT_NEXT_USHORT( p );
+        }
+        charcode = PFR_KERN_INDEX( char1, char2 );
+
+        if ( idx == charcode )
+        {
+          if ( item->flags & PFR_KERN_2BYTE_ADJ )
+            kerning->x = item->base_adj + FT_NEXT_SHORT( p );
+          else
+            kerning->x = item->base_adj + FT_NEXT_CHAR( p );
+
+          break;
+        }
+        if ( idx > charcode )
+          min = mid + 1;
+        else
+          max = mid;
+      }
+
+      FT_FRAME_EXIT();
+    }
+
+  Exit:
+    return 0;
+  }
+
+/* END */