Пример #1
0
bool FontPlatformData::hasSpaceInLigaturesOrKerning(
    TypesettingFeatures features) const {
  HarfBuzzFace* hbFace = harfBuzzFace();
  if (!hbFace)
    return false;

  hb_font_t* font = hbFace->getScaledFont();
  ASSERT(font);
  hb_face_t* face = hb_font_get_face(font);
  ASSERT(face);

  hb_codepoint_t space;
  // If the space glyph isn't present in the font then each space character
  // will be rendering using a fallback font, which grantees that it cannot
  // affect the shape of the preceding word.
  if (!hb_font_get_glyph(font, spaceCharacter, 0, &space))
    return false;

  if (!hb_ot_layout_has_substitution(face) &&
      !hb_ot_layout_has_positioning(face)) {
    return false;
  }

  bool foundSpaceInTable = false;
  hb_set_t* glyphs = hb_set_create();
  if (features & Kerning)
    foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GPOS, space);
  if (!foundSpaceInTable && (features & Ligatures))
    foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GSUB, space);

  hb_set_destroy(glyphs);

  return foundSpaceInTable;
}
Пример #2
0
long
findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, uint32_t id, const char* name, int namelength)
{
    long rval = -1;

    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL) {
        const gr_feature_ref* feature = gr_face_find_fref(grFace, id);
        for (int i = 0; i < gr_fref_n_values(feature); i++) {
            uint32_t len = 0;
            uint16_t langID = 0x409;

            // the first call is to get the length of the string
            gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
            char* label = (char*) xmalloc(len);
            label = (char*) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);

            if (strncmp(label, name, namelength) == 0) {
                rval = gr_fref_value(feature, i);
                gr_label_destroy(label);
                break;
            }

            gr_label_destroy(label);
        }
    }

    return rval;
}
Пример #3
0
hb_tag_t
getIndFeature(XeTeXFont font, hb_tag_t script, hb_tag_t language, unsigned int index)
{
    hb_tag_t rval = 0;

    hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());

    for (int i = 0; i < 2; ++i) {
        unsigned int scriptIndex, langIndex = 0;
        hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
        if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
            if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
                unsigned int featCount = hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
                hb_tag_t* featList = (hb_tag_t*) xcalloc(featCount, sizeof(hb_tag_t*));
                hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, &featCount, featList);

                if (index < featCount) {
                    rval = featList[index];
                    break;
                }

                index -= featCount;
            }
        }
    }

    return rval;
}
Пример #4
0
bool
initGraphiteBreaking(XeTeXLayoutEngine engine, const uint16_t* txtPtr, int txtLen)
{
    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
    gr_font* grFont = hb_graphite2_font_get_gr_font(engine->font->getHbFont());
    if (grFace != NULL && grFont != NULL) {
        if (grSegment != NULL) {
            gr_seg_destroy(grSegment);
            grSegment = NULL;
            grPrevSlot = NULL;
        }

        gr_feature_val *grFeatureValues = gr_face_featureval_for_lang (grFace, tag_from_lang(engine->language));

        int nFeatures = engine->nFeatures;
        hb_feature_t *features =  engine->features;
        while (nFeatures--) {
            const gr_feature_ref *fref = gr_face_find_fref (grFace, features->tag);
            if (fref)
                gr_fref_set_feature_value (fref, features->value, grFeatureValues);
            features++;
        }

        grSegment = gr_make_seg(grFont, grFace, engine->script, grFeatureValues, gr_utf16, txtPtr, txtLen, 0);
        grPrevSlot = gr_seg_first_slot(grSegment);
        grTextLen = txtLen;

        return true;
    }

    return false;
}
Пример #5
0
static unsigned int
getLargerScriptListTable(XeTeXFont font, hb_tag_t** scriptList)
{
    unsigned int rval = 0;

    hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());

    hb_tag_t* scriptListSub = NULL;
    hb_tag_t* scriptListPos = NULL;

    unsigned int scriptCountSub = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, NULL, NULL);
    scriptListSub = (hb_tag_t*) xcalloc(scriptCountSub, sizeof(hb_tag_t*));
    hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountSub, scriptListSub);

    unsigned int scriptCountPos = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GPOS, 0, NULL, NULL);
    scriptListPos = (hb_tag_t*) xcalloc(scriptCountPos, sizeof(hb_tag_t*));
    hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountPos, scriptListPos);

    if (scriptCountSub > scriptCountPos) {
        if (scriptList != NULL)
            *scriptList = scriptListSub;
        rval = scriptCountSub;
    } else {
        if (scriptList != NULL)
            *scriptList = scriptListPos;
        rval = scriptCountPos;
    }

    return rval;
}
Пример #6
0
hb_blob_t* getFontTable(const MinikinFont* minikinFont, uint32_t tag) {
    assertMinikinLocked();
    hb_font_t* font = getHbFontLocked(minikinFont);
    hb_face_t* face = hb_font_get_face(font);
    hb_blob_t* blob = hb_face_reference_table(face, tag);
    hb_font_destroy(font);
    return blob;
}
Пример #7
0
uint32_t
countGraphiteFeatures(XeTeXLayoutEngine engine)
{
    uint32_t rval = 0;

    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL)
        rval = gr_face_n_fref(grFace);

    return rval;
}
Пример #8
0
uint32_t
getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, uint32_t featureID, uint32_t index)
{
    uint32_t rval = 0;

    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL) {
        const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
        rval = gr_fref_value(feature, index);
    }

    return rval;
}
Пример #9
0
char *
getGraphiteFeatureLabel(XeTeXLayoutEngine engine, uint32_t featureID)
{
    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL) {
        const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
        uint32_t len = 0;
        uint16_t langID = 0x409;

        return (char *) gr_fref_label(feature, &langID, gr_utf8, &len);
    }

    return NULL;
}
Пример #10
0
uint32_t
getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine, uint32_t featureID)
{
    uint32_t rval = 0;

    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL) {
        const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
        gr_feature_val *featureValues = gr_face_featureval_for_lang (grFace, tag_from_lang(engine->language));

        rval = gr_fref_feature_value(feature, featureValues);
    }

    return rval;
}
Пример #11
0
unsigned int
countFeatures(XeTeXFont font, hb_tag_t script, hb_tag_t language)
{
    unsigned int rval = 0;

    hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());

    for (int i = 0; i < 2; ++i) {
        unsigned int scriptIndex, langIndex = 0;
        hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
        if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
            if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
                rval += hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
            }
        }
    }

    return rval;
}
Пример #12
0
hb_tag_t
getIndLanguage(XeTeXFont font, hb_tag_t script, unsigned int index)
{
    hb_tag_t rval = 0;

    hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
    hb_tag_t* scriptList;

    unsigned int scriptCount = getLargerScriptListTable(font, &scriptList);
    if (scriptList != NULL) {
        for (int i = 0; i < scriptCount; i++) {
            if (scriptList[i] == script) {
                unsigned int langCount;
                hb_tag_t* langList;

                langCount = hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, NULL, NULL);
                langList = (hb_tag_t*) xcalloc(langCount, sizeof(hb_tag_t*));
                hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, &langCount, langList);

                if (index < langCount) {
                    rval = langList[index];
                    break;
                }

                free(langList);

                langCount = hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GPOS, i, 0, NULL, NULL);
                langList = (hb_tag_t*) xcalloc(langCount, sizeof(hb_tag_t*));
                hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GPOS, i, 0, &langCount, langList);

                if (index < langCount) {
                    rval = langList[index];
                    break;
                }

                free(langList);
            }
        }
    }

    return rval;
}
Пример #13
0
char *
getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, uint32_t featureID, uint32_t settingID)
{
    hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
    gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);

    if (grFace != NULL) {
        const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
        for (int i = 0; i < gr_fref_n_values(feature); i++) {
            if (settingID == gr_fref_value(feature, i)) {
                uint32_t len = 0;
                uint16_t langID = 0x409;

                return (char *) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
            }
        }
    }

    return NULL;
}
Пример #14
0
unsigned int
countLanguages(XeTeXFont font, hb_tag_t script)
{
    unsigned int rval = 0;

    hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
    hb_tag_t* scriptList;

    unsigned int scriptCount = getLargerScriptListTable(font, &scriptList);
    if (scriptList != NULL) {
        for (int i = 0; i < scriptCount; i++) {
            if (scriptList[i] == script) {
                rval += hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GSUB, i, 0, NULL, NULL);
                rval += hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GPOS, i, 0, NULL, NULL);
                break;
            }
        }
    }

    return rval;
}
Пример #15
0
const XeTeXFontMgr::OpSizeRec*
XeTeXFontMgr::getOpSize(XeTeXFont font)
{
    hb_font_t* hbFont = ((XeTeXFontInst*)font)->getHbFont();
    if (hbFont != NULL) {
        hb_face_t* face = hb_font_get_face(hbFont);
        OpSizeRec* pSizeRec = (OpSizeRec*) xmalloc(sizeof(OpSizeRec));

        bool ok = hb_ot_layout_get_size_params(face,
                &pSizeRec->designSize,
                &pSizeRec->subFamilyID,
                &pSizeRec->nameCode,
                &pSizeRec->minSize,
                &pSizeRec->maxSize);

        if (ok)
            return pSizeRec;

        free(pSizeRec);
        return NULL;
    }

    return NULL;
}
Пример #16
0
  FT_Error
  af_get_coverage( AF_FaceGlobals  globals,
                   AF_StyleClass   style_class,
                   FT_UShort*      gstyles )
  {
    hb_face_t*  face;

    hb_set_t*  gsub_lookups;  /* GSUB lookups for a given script */
    hb_set_t*  gsub_glyphs;   /* glyphs covered by GSUB lookups  */
    hb_set_t*  gpos_lookups;  /* GPOS lookups for a given script */
    hb_set_t*  gpos_glyphs;   /* glyphs covered by GPOS lookups  */

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

    hb_codepoint_t  idx;
#ifdef FT_DEBUG_LEVEL_TRACE
    int             count;
#endif


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

    face = hb_font_get_face( globals->hb_font );

    gsub_lookups = hb_set_create();
    gsub_glyphs  = hb_set_create();
    gpos_lookups = hb_set_create();
    gpos_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 except for the  */
    /* default script.                                                   */
    if ( style_class->script == globals->module->default_script &&
         style_class->coverage == AF_COVERAGE_DEFAULT           )
    {
      if ( script_tags[0] == HB_TAG_NONE )
        script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT;
      else
      {
        if ( script_tags[1] == HB_TAG_NONE )
          script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT;
        else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT )
          script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT;
      }
    }
    else
    {
      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,
                                  gsub_lookups );

    if ( hb_set_is_empty( gsub_lookups ) )
      goto Exit; /* nothing to do */

    hb_ot_layout_collect_lookups( face,
                                  HB_OT_TAG_GPOS,
                                  script_tags,
                                  NULL,
                                  coverage_tags,
                                  gpos_lookups );

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

#ifdef FT_DEBUG_LEVEL_TRACE
    count = 0;
#endif

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

      /* get output coverage of GSUB feature */
      hb_ot_layout_lookup_collect_glyphs( face,
                                          HB_OT_TAG_GSUB,
                                          idx,
                                          NULL,
                                          NULL,
                                          NULL,
                                          gsub_glyphs );
    }

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

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

#ifdef FT_DEBUG_LEVEL_TRACE
    count = 0;
#endif

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

      /* get input coverage of GPOS feature */
      hb_ot_layout_lookup_collect_glyphs( face,
                                          HB_OT_TAG_GPOS,
                                          idx,
                                          NULL,
                                          gpos_glyphs,
                                          NULL,
                                          NULL );
    }

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

    /*
     * We now check whether we can construct blue zones, using glyphs
     * covered by the feature only.  In case there is not a single zone
     * (this is, not a single character is covered), we skip this coverage.
     *
     */
    if ( style_class->coverage != AF_COVERAGE_DEFAULT )
    {
      AF_Blue_Stringset         bss = style_class->blue_stringset;
      const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];

      FT_Bool  found = 0;


      for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
      {
        const char*  p = &af_blue_strings[bs->string];


        while ( *p )
        {
          hb_codepoint_t  ch;


          GET_UTF8_CHAR( ch, p );

          for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups,
                                                         &idx ); )
          {
            hb_codepoint_t  gidx = FT_Get_Char_Index( globals->face, ch );


            if ( hb_ot_layout_lookup_would_substitute( face, idx,
                                                       &gidx, 1, 1 ) )
            {
              found = 1;
              break;
            }
          }
        }
      }

      if ( !found )
      {
        FT_TRACE4(( "  no blue characters found; style skipped\n" ));
        goto Exit;
      }
    }

    /*
     * Various OpenType features might use the same glyphs at different
     * vertical positions; for example, superscript and subscript glyphs
     * could be the same.  However, the auto-hinter is completely
     * agnostic of OpenType features after the feature analysis has been
     * completed: The engine then simply receives a glyph index and returns a
     * hinted and usually rendered glyph.
     *
     * Consider the superscript feature of font `pala.ttf': Some of the
     * glyphs are `real', this is, they have a zero vertical offset, but
     * most of them are small caps glyphs shifted up to the superscript
     * position (this is, the `sups' feature is present in both the GSUB and
     * GPOS tables).  The code for blue zones computation actually uses a
     * feature's y offset so that the `real' glyphs get correct hints.  But
     * later on it is impossible to decide whether a glyph index belongs to,
     * say, the small caps or superscript feature.
     *
     * For this reason, we don't assign a style to a glyph if the current
     * feature covers the glyph in both the GSUB and the GPOS tables.  This
     * is quite a broad condition, assuming that
     *
     *   (a) glyphs that get used in multiple features are present in a
     *       feature without vertical shift,
     *
     * and
     *
     *   (b) a feature's GPOS data really moves the glyph vertically.
     *
     * Not fulfilling condition (a) makes a font larger; it would also
     * reduce the number of glyphs that could be addressed directly without
     * using OpenType features, so this assumption is rather strong.
     *
     * Condition (b) is much weaker, and there might be glyphs which get
     * missed.  However, the OpenType features we are going to handle are
     * primarily located in GSUB, and HarfBuzz doesn't provide an API to
     * directly get the necessary information from the GPOS table.  A
     * possible solution might be to directly parse the GPOS table to find
     * out whether a glyph gets shifted vertically, but this is something I
     * would like to avoid if not really necessary.
     *
     * Note that we don't follow this logic for the default coverage.
     * Complex scripts like Devanagari have mandatory GPOS features to
     * position many glyph elements, using mark-to-base or mark-to-ligature
     * tables; the number of glyphs missed due to condition (b) would be far
     * too large.
     *
     */
    if ( style_class->coverage != AF_COVERAGE_DEFAULT )
      hb_set_subtract( gsub_glyphs, gpos_glyphs );

#ifdef FT_DEBUG_LEVEL_TRACE
    FT_TRACE4(( "  glyphs without GPOS data (`*' means already assigned)" ));
    count = 0;
#endif

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

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

      /* glyph indices returned by `hb_ot_layout_lookup_collect_glyphs' */
      /* can be arbitrary: some fonts use fake indices for processing   */
      /* internal to GSUB or GPOS, which is fully valid                 */
      if ( idx >= (hb_codepoint_t)globals->glyph_count )
        continue;

      if ( gstyles[idx] == AF_STYLE_UNASSIGNED )
        gstyles[idx] = (FT_UShort)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

  Exit:
    hb_set_destroy( gsub_lookups );
    hb_set_destroy( gsub_glyphs  );
    hb_set_destroy( gpos_lookups );
    hb_set_destroy( gpos_glyphs  );

    return FT_Err_Ok;
  }
Пример #17
0
int shape (lua_State *L) {    
    const char * text = luaL_checkstring(L, 1);
    FT_Face face = lua_touserdata(L, 2);
    const char * script = luaL_checkstring(L, 3);
    const char * direction_s = luaL_checkstring(L, 4);
    const char * lang = luaL_checkstring(L, 5);
    double point_size = luaL_checknumber(L, 6);
    const char * featurestring = luaL_checkstring(L, 7);

    hb_segment_properties_t segment_props;
    hb_shape_plan_t *shape_plan;

    hb_direction_t direction;
    hb_feature_t* features;
    int nFeatures = 0;
    unsigned int glyph_count = 0;
    hb_font_t *hb_ft_font;
    hb_face_t *hb_ft_face;
    hb_buffer_t *buf;
    hb_glyph_info_t *glyph_info;
    hb_glyph_position_t *glyph_pos;
    unsigned int j;

    features = scan_feature_string(featurestring, &nFeatures);

    if (!strcasecmp(direction_s,"RTL"))
      direction = HB_DIRECTION_RTL;
    else if (!strcasecmp(direction_s,"TTB"))
      direction = HB_DIRECTION_TTB;
    else
      direction = HB_DIRECTION_LTR;

    hb_ft_font = hb_ft_font_create(face, NULL);
    hb_face_t* hbFace = hb_font_get_face(hb_ft_font);

    buf = hb_buffer_create();
    hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));

    hb_buffer_set_script(buf, hb_tag_from_string(script, strlen(script)));
    hb_buffer_set_direction(buf, direction);
    hb_buffer_set_language(buf, hb_language_from_string(lang,strlen(lang)));

    hb_buffer_guess_segment_properties(buf);
    hb_buffer_get_segment_properties(buf, &segment_props);
    shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, features, nFeatures, NULL);
    int res = hb_shape_plan_execute(shape_plan, hb_ft_font, buf, features, nFeatures);

    glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
    glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);
    lua_checkstack(L, glyph_count);
    for (j = 0; j < glyph_count; ++j) {
      char namebuf[255];
      box glyph_extents  = { 0.0, 0.0, 0.0 };
      calculate_extents(&glyph_extents, glyph_info[j], glyph_pos[j], face, point_size, direction);

      lua_newtable(L);
      lua_pushstring(L, "name");
      FT_Get_Glyph_Name( face, glyph_info[j].codepoint, namebuf, 255 );      
      lua_pushstring(L, namebuf);
      lua_settable(L, -3);

      if (direction != HB_DIRECTION_TTB) { /* XXX */
        if (glyph_pos[j].x_offset) {
          lua_pushstring(L, "x_offset");
          lua_pushnumber(L, glyph_pos[j].x_offset / 64.0);
          lua_settable(L, -3);
        }

        if (glyph_pos[j].y_offset) {
          lua_pushstring(L, "y_offset");
          lua_pushnumber(L, glyph_pos[j].y_offset / 64.0);
          lua_settable(L, -3);
        }
      }

      lua_pushstring(L, "codepoint");
      lua_pushinteger(L, glyph_info[j].codepoint);
      lua_settable(L, -3);
      lua_pushstring(L, "width");
      lua_pushnumber(L, glyph_extents.width);
      lua_settable(L, -3);
      lua_pushstring(L, "height");
      lua_pushnumber(L, glyph_extents.height);
      lua_settable(L, -3);
      lua_pushstring(L, "depth");
      lua_pushnumber(L, glyph_extents.depth);
      lua_settable(L, -3);
    }
    /* Cleanup */
    hb_buffer_destroy(buf);
    hb_font_destroy(hb_ft_font);
    hb_shape_plan_destroy(shape_plan);

    free(features);
    return glyph_count;
}
Пример #18
0
bool OpenTypeCapsSupport::supportsOpenTypeFeature(
    hb_script_t script,
    uint32_t tag) const
{
    hb_face_t* face = hb_font_get_face(m_harfBuzzFace->getScaledFont());
    ASSERT(face);

    ASSERT((tag == HB_TAG('s', 'm', 'c', 'p')
        || tag == HB_TAG('c', '2', 's', 'c')
        || tag == HB_TAG('p', 'c', 'a', 'p')
        || tag == HB_TAG('c', '2', 'p', 'c')
        || tag == HB_TAG('s', 'u', 'p', 's')
        || tag == HB_TAG('s', 'u', 'b', 's')
        || tag == HB_TAG('t', 'i', 't', 'l')
        || tag == HB_TAG('u', 'n', 'i', 'c')
        || tag == HB_TAG('v', 'e', 'r', 't')));

    bool result = false;

    if (!hb_ot_layout_has_substitution(face))
        return false;

    // Get the OpenType tag(s) that match this script code
    const size_t kMaxScriptTags = 4;
    hb_tag_t scriptTags[kMaxScriptTags] = {
        HB_TAG_NONE,
        HB_TAG_NONE,
        HB_TAG_NONE,
        HB_TAG_NONE
    };
    hb_ot_tags_from_script(static_cast<hb_script_t>(script),
        &scriptTags[0],
        &scriptTags[1]);

    // Replace the first remaining NONE with DEFAULT
    for (size_t i = 0; i < kMaxScriptTags; ++i) {
        if (scriptTags[i] == HB_TAG_NONE) {
            scriptTags[i] = HB_OT_TAG_DEFAULT_SCRIPT;
            break;
        }
    }

    // Now check for 'smcp' under the first of those scripts that is present
    const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
    for (size_t j = 0; j < kMaxScriptTags; ++j) {
        if (scriptTags[j] == HB_TAG_NONE)
            break;

        unsigned scriptIndex;
        if (hb_ot_layout_table_find_script(face,
            kGSUB,
            scriptTags[j],
            &scriptIndex)) {
            if (hb_ot_layout_language_find_feature(face, kGSUB,
                scriptIndex,
                HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
                tag, nullptr)) {
                result = true;
            }
            break;
        }
    }
    return result;
}
Пример #19
0
int
layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t count, int32_t max,
                        bool rightToLeft)
{
    bool res;
    hb_script_t script = HB_SCRIPT_INVALID;
    hb_direction_t direction = HB_DIRECTION_LTR;
    hb_segment_properties_t segment_props;
    hb_shape_plan_t *shape_plan;
    hb_font_t* hbFont = engine->font->getHbFont();
    hb_face_t* hbFace = hb_font_get_face(hbFont);

    if (engine->font->getLayoutDirVertical())
        direction = HB_DIRECTION_TTB;
    else if (rightToLeft)
        direction = HB_DIRECTION_RTL;

    script = hb_ot_tag_to_script (engine->script);

    if (hbUnicodeFuncs == NULL)
        hbUnicodeFuncs = _get_unicode_funcs();

    hb_buffer_reset(engine->hbBuffer);
    hb_buffer_set_unicode_funcs(engine->hbBuffer, hbUnicodeFuncs);
    hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count);
    hb_buffer_set_direction(engine->hbBuffer, direction);
    hb_buffer_set_script(engine->hbBuffer, script);
    hb_buffer_set_language(engine->hbBuffer, engine->language);

    hb_buffer_guess_segment_properties(engine->hbBuffer);
    hb_buffer_get_segment_properties(engine->hbBuffer, &segment_props);

    if (engine->ShaperList == NULL) {
        // HarfBuzz gives graphite2 shaper a priority, so that for hybrid
        // Graphite/OpenType fonts, Graphite will be used. However, pre-0.9999
        // XeTeX preferred OpenType over Graphite, so we are doing the same
        // here for sake of backward compatibility.
        engine->ShaperList = (char**) xcalloc(4, sizeof(char*));
        engine->ShaperList[0] = (char*) "ot";
        engine->ShaperList[1] = (char*) "graphite2";
        engine->ShaperList[2] = (char*) "fallback";
        engine->ShaperList[3] = NULL;
    }

    shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, engine->features, engine->nFeatures, engine->ShaperList);
    res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures);

    if (res) {
        engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan));
        hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
    } else {
        // all selected shapers failed, retrying with default
        // we don't use _cached here as the cached plain will always fail.
        hb_shape_plan_destroy(shape_plan);
        shape_plan = hb_shape_plan_create(hbFace, &segment_props, engine->features, engine->nFeatures, NULL);
        res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures);

        if (res) {
            engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan));
            hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
        } else {
            fprintf(stderr, "\nERROR: all shapers failed\n");
            exit(3);
        }
    }

    hb_shape_plan_destroy(shape_plan);

    int glyphCount = hb_buffer_get_length(engine->hbBuffer);

#ifdef DEBUG
    char buf[1024];
    unsigned int consumed;

    printf ("shaper: %s\n", engine->shaper);

    hb_buffer_serialize_flags_t flags = HB_BUFFER_SERIALIZE_FLAGS_DEFAULT;
    hb_buffer_serialize_format_t format = HB_BUFFER_SERIALIZE_FORMAT_JSON;

    hb_buffer_serialize_glyphs (engine->hbBuffer, 0, glyphCount, buf, sizeof(buf), &consumed, hbFont, format, flags);
    if (consumed)
        printf ("buffer glyphs: %s\n", buf);
#endif

    return glyphCount;
}