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; }
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; }