shithub: freetype+ttf2subf

ref: 00a7b51fab76e8331f4ae86507e468b79856b47e
dir: /src/autofit/hbshim.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  hbshim.c                                                               */
/*                                                                         */
/*    HarfBuzz interface for accessing OpenType features (body).           */
/*                                                                         */
/*  Copyright 2013 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 <ft2build.h>
#include FT_FREETYPE_H


#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ

#include <hb.h>
#include <hb-ot.h>
#include <hb-ft.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  trace_afharfbuzz


  /*
   * We use `sets' (in the HarfBuzz sense, which comes quite near to the
   * usual mathematical meaning) to manage both lookups and glyph indices.
   *
   * 1. For each coverage, collect lookup IDs in a set.  Note that an
   *    auto-hinter `coverage' is represented by one or more `feature's, and
   *    a feature consists of an arbitrary number of (font specific)
   *    `lookup's that actually do the mapping job.  Please check the
   *    OpenType specification for more details on features and lookups.
   *
   * 2. Create glyph ID sets from the corresponding lookup sets.
   *
   * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed
   *    with all lookups specific to the OpenType script activated.  It
   *    relies on the order of AF_DEFINE_STYLE_CLASS entries so that
   *    special coverages (like `oldstyle figures') don't get overwritten.
   *
   */


  /* load coverage tags */
#undef  COVERAGE_1
#define COVERAGE_1( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4 )   \
          static const hb_tag_t  name ## _coverage[] = \
          {                                            \
            HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ),  \
            HB_TAG_NONE                                \
          };

#undef  COVERAGE_2
#define COVERAGE_2( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4,    \
                    tag_b1, tag_b2, tag_b3, tag_b4 )   \
          static const hb_tag_t  name ## _coverage[] = \
          {                                            \
            HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ),  \
            HB_TAG( tag_b1, tag_b2, tag_b3, tag_b4 ),  \
            HB_TAG_NONE                                \
          };

#undef  COVERAGE_3
#define COVERAGE_3( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4,    \
                    tag_b1, tag_b2, tag_b3, tag_b4,    \
                    tag_c1, tag_c2, tag_c3, tag_c4 )   \
          static const hb_tag_t  name ## _coverage[] = \
          {                                            \
            HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ),  \
            HB_TAG( tag_b1, tag_b2, tag_b3, tag_b4 ),  \
            HB_TAG( tag_c1, tag_c2, tag_c3, tag_c4 ),  \
            HB_TAG_NONE                                \
          };


#include "afcover.h"


  /* define mapping between coverage tags and AF_Coverage */
#undef  COVERAGE_1
#define COVERAGE_1( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4 )   \
          name ## _coverage,

#undef  COVERAGE_2
#define COVERAGE_2( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4,    \
                    tag_b1, tag_b2, tag_b3, tag_b4 )   \
          name ## _coverage,

#undef  COVERAGE_3
#define COVERAGE_3( name, NAME, description,           \
                    tag_a1, tag_a2, tag_a3, tag_a4,    \
                    tag_b1, tag_b2, tag_b3, tag_b4,    \
                    tag_c1, tag_c2, tag_c3, tag_c4 )   \
          name ## _coverage,


  static const hb_tag_t*  coverages[] =
  {
#include "afcover.h"

    NULL /* AF_COVERAGE_DEFAULT */
  };


  /* load HarfBuzz script tags */
#undef  SCRIPT
#define SCRIPT( s, S, d, h, dc )  h,


  static const hb_tag_t  scripts[] =
  {
#include "afscript.h"
  };


  FT_Error
  af_get_coverage( FT_Face        ft_face,
                   AF_StyleClass  style_class,
                   FT_Byte*       gstyles )
  {
    hb_face_t*  face;

    hb_set_t*  lookups;  /* lookups for a given script */
    hb_set_t*  glyphs;   /* glyphs covered by lookups  */

    hb_tag_t         script;
    const hb_tag_t*  coverage_tags;
    hb_tag_t         script_tags[] = { HB_TAG_NONE,
                                       HB_TAG_NONE,
                                       HB_TAG_NONE };

    hb_codepoint_t  idx;
#ifdef FT_DEBUG_LEVEL_TRACE
    int             count;
#endif


    if ( !ft_face || !style_class || !gstyles )
      return FT_THROW( Invalid_Argument );

    face = hb_ft_face_create( ft_face, NULL );

    lookups = hb_set_create();
    glyphs  = hb_set_create();

    coverage_tags = coverages[style_class->coverage];
    script        = scripts[style_class->script];

    /* Convert a HarfBuzz script tag into the corresponding OpenType */
    /* tag or tags -- some Indic scripts like Devanagari have an old */
    /* and a new set of features.                                    */
    hb_ot_tags_from_script( script,
                            &script_tags[0],
                            &script_tags[1] );

    /* `hb_ot_tags_from_script' usually returns HB_OT_TAG_DEFAULT_SCRIPT */
    /* as the second tag.  We change that to HB_TAG_NONE since the       */
    /* default script gets handled later on.                             */
    if ( script_tags[1] == HB_OT_TAG_DEFAULT_SCRIPT )
      script_tags[1] = HB_TAG_NONE;

    hb_ot_layout_collect_lookups( face,
                                  HB_OT_TAG_GSUB,
                                  script_tags,
                                  NULL,
                                  coverage_tags,
                                  lookups );

    FT_TRACE4(( "lookups (style `%s'):\n"
                " ",
                af_style_names[style_class->style] ));

#ifdef FT_DEBUG_LEVEL_TRACE
    count = 0;
#endif

    for ( idx = -1; hb_set_next( lookups, &idx ); )
    {
#ifdef FT_DEBUG_LEVEL_TRACE
      FT_TRACE4(( " %d", idx ));
      count++;
#endif

      hb_ot_layout_lookup_collect_glyphs( face,
                                          HB_OT_TAG_GSUB,
                                          idx,
                                          NULL,
                                          NULL,
                                          NULL,
                                          glyphs );
    }

#ifdef FT_DEBUG_LEVEL_TRACE
    if ( !count )
      FT_TRACE4(( " (none)" ));
    FT_TRACE4(( "\n\n" ));

    FT_TRACE4(( "  glyphs (`*' means already assigned)" ));

    count = 0;
#endif

    for ( idx = -1; hb_set_next( glyphs, &idx ); )
    {
#ifdef FT_DEBUG_LEVEL_TRACE
      if ( !( count % 10 ) )
        FT_TRACE4(( "\n"
                    "   " ));

      FT_TRACE4(( " %d", idx ));
      count++;
#endif

      if ( gstyles[idx] == AF_STYLE_UNASSIGNED )
        gstyles[idx] = (FT_Byte)style_class->style;
#ifdef FT_DEBUG_LEVEL_TRACE
      else
        FT_TRACE4(( "*" ));
#endif
    }

#ifdef FT_DEBUG_LEVEL_TRACE
    if ( !count )
      FT_TRACE4(( "\n"
                  "    (none)" ));
    FT_TRACE4(( "\n\n" ));
#endif

    hb_set_destroy( lookups );
    hb_set_destroy( glyphs  );

    hb_face_destroy( face );

    return FT_Err_Ok;
  }


#if 0
  /* to be always excluded */
  COVERAGE(nalt, 'n', 'a', 'l', 't'); /* Alternate Annotation Forms (?) */
  COVERAGE(ornm, 'o', 'r', 'n', 'm'); /* Ornaments (?) */
  /* COVERAGE(ruby, 'r', 'u', 'b', 'y') */ /* (only for Japanese) */
#endif

#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */


/* END */