bool FontPlatformData::hasSpaceInLigaturesOrKerning(
    TypesettingFeatures features) const
{
    const HarfBuzzFace* hbFace = harfBuzzFace();
    if (!hbFace)
        return false;

    hb_face_t* face = hbFace->face();
    ASSERT(face);
    OwnPtr<hb_font_t> font = adoptPtr(hbFace->createFont());
    ASSERT(font);

    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.get(), 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;
}
Exemple #2
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;
}