namespace HBFeature { const hb_tag_t KernTag = HB_TAG('k', 'e', 'r', 'n'); // kerning operations const hb_tag_t LigaTag = HB_TAG('l', 'i', 'g', 'a'); // standard ligature substitution const hb_tag_t CligTag = HB_TAG('c', 'l', 'i', 'g'); // contextual ligature substitution static hb_feature_t LigatureOn = { LigaTag, 1, 0, std::numeric_limits<unsigned int>::max() }; static hb_feature_t KerningOn = { KernTag, 1, 0, std::numeric_limits<unsigned int>::max() }; static hb_feature_t CligOn = { CligTag, 1, 0, std::numeric_limits<unsigned int>::max() }; }
/** * \brief set up the HarfBuzz OpenType feature list with some * standard features. */ static void init_features(ASS_Shaper *shaper) { shaper->features = calloc(sizeof(hb_feature_t), NUM_FEATURES); shaper->n_features = NUM_FEATURES; shaper->features[VERT].tag = HB_TAG('v', 'e', 'r', 't'); shaper->features[VERT].end = INT_MAX; shaper->features[VKNA].tag = HB_TAG('v', 'k', 'n', 'a'); shaper->features[VKNA].end = INT_MAX; shaper->features[KERN].tag = HB_TAG('k', 'e', 'r', 'n'); shaper->features[KERN].end = INT_MAX; }
void HarfBuzzShaper::setFontFeatures() { const FontDescription& description = m_font->fontDescription(); if (description.orientation() == Vertical) { static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) }; static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) }; m_features.append(vert); m_features.append(vrt2); } FontFeatureSettings* settings = description.featureSettings(); if (!settings) return; unsigned numFeatures = settings->size(); for (unsigned i = 0; i < numFeatures; ++i) { hb_feature_t feature; const UChar* tag = settings->at(i).tag().characters(); feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); feature.value = settings->at(i).value(); feature.start = 0; feature.end = static_cast<unsigned>(-1); m_features.append(feature); } }
static void override_features_hangul (hb_ot_shape_planner_t *plan) { /* Uniscribe does not apply 'calt' for Hangul, and certain fonts * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups * in calt, which is not desirable. */ plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL); }
static inline hb_feature_t createFeature(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4, uint32_t value = 0) { return {HB_TAG(c1, c2, c3, c4), value, 0 /* start */, static_cast<unsigned>(-1) /* end */}; }
void CapsFeatureSettingsScopedOverlay::overlayCapsFeatures( FontDescription::FontVariantCaps variantCaps) { static hb_feature_t smcp = createFeature(HB_TAG('s', 'm', 'c', 'p'), 1); static hb_feature_t pcap = createFeature(HB_TAG('p', 'c', 'a', 'p'), 1); static hb_feature_t c2sc = createFeature(HB_TAG('c', '2', 's', 'c'), 1); static hb_feature_t c2pc = createFeature(HB_TAG('c', '2', 'p', 'c'), 1); static hb_feature_t unic = createFeature(HB_TAG('u', 'n', 'i', 'c'), 1); static hb_feature_t titl = createFeature(HB_TAG('t', 'i', 't', 'l'), 1); if (variantCaps == FontDescription::SmallCaps || variantCaps == FontDescription::AllSmallCaps) { prependCounting(smcp); if (variantCaps == FontDescription::AllSmallCaps) { prependCounting(c2sc); } } if (variantCaps == FontDescription::PetiteCaps || variantCaps == FontDescription::AllPetiteCaps) { prependCounting(pcap); if (variantCaps == FontDescription::AllPetiteCaps) { prependCounting(c2pc); } } if (variantCaps == FontDescription::Unicase) { prependCounting(unic); } if (variantCaps == FontDescription::TitlingCaps) { prependCounting(titl); } }
static void collect_features_arabic (hb_ot_shape_planner_t *plan) { hb_ot_map_builder_t *map = &plan->map; /* We apply features according to the Arabic spec, with pauses * in between most. * * The pause between init/medi/... and rlig is required. See eg: * https://bugzilla.mozilla.org/show_bug.cgi?id=644184 * * The pauses between init/medi/... themselves are not necessarily * needed as only one of those features is applied to any character. * The only difference it makes is when fonts have contextual * substitutions. We now follow the order of the spec, which makes * for better experience if that's what Uniscribe is doing. * * At least for Arabic, looks like Uniscribe has a pause between * rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't * work. However, testing shows that rlig and calt are applied * together for Mongolian in Uniscribe. As such, we only add a * pause for Arabic, not other scripts. */ map->add_gsub_pause (nuke_joiners); map->add_global_bool_feature (HB_TAG('s','t','c','h')); map->add_gsub_pause (record_stch); map->add_global_bool_feature (HB_TAG('c','c','m','p')); map->add_global_bool_feature (HB_TAG('l','o','c','l')); map->add_gsub_pause (NULL); for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]); map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE); map->add_gsub_pause (NULL); } map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); if (plan->props.script == HB_SCRIPT_ARABIC) map->add_gsub_pause (arabic_fallback_shape); map->add_global_bool_feature (HB_TAG('c','a','l','t')); /* The spec includes 'cswh'. Earlier versions of Windows * used to enable this by default, but testing suggests * that Windows 8 and later do not enable it by default, * and spec now says 'Off by default'. * We disabled this in ae23c24c32. * Note that IranNastaliq uses this feature extensively * to fixup broken glyph sequences. Oh well... * Test case: U+0643,U+0640,U+0631. */ //map->add_gsub_pause (NULL); //map->add_global_bool_feature (HB_TAG('c','s','w','h')); map->add_global_bool_feature (HB_TAG('m','s','e','t')); }
void HarfBuzzShaper::setFontFeatures() { FontFeatureSettings* settings = m_font->fontDescription().featureSettings(); if (!settings) return; unsigned numFeatures = settings->size(); m_features.resize(numFeatures); for (unsigned i = 0; i < numFeatures; ++i) { const UChar* tag = settings->at(i).tag().characters(); m_features[i].tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); m_features[i].value = settings->at(i).value(); m_features[i].start = 0; m_features[i].end = static_cast<unsigned>(-1); } }
void * data_create_arabic (const hb_ot_shape_plan_t *plan) { arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t)); if (unlikely (!arabic_plan)) return NULL; arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC; arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h')); for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); arabic_plan->do_fallback = arabic_plan->do_fallback && (FEATURE_IS_SYRIAC (arabic_features[i]) || plan->map.needs_fallback (arabic_features[i])); } return arabic_plan; }
static void test_subset_cff1_seac (void) { hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf"); hb_face_t *face_subset = hb_test_open_font_file ("fonts/cff1_seac.C0.otf"); hb_face_t *face_test; hb_set_t *codepoints = hb_set_create (); hb_set_add (codepoints, 0xC0); /* Agrave */ face_test = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_subset, face_test, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_test); hb_face_destroy (face_subset); hb_face_destroy (face); }
static void test_subset_cff1_noop (void) { hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansPro-Regular.abc.otf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_abc_subset; hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'b'); hb_set_add (codepoints, 'c'); face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); }
static void test_subset_hdmx_multiple_device_records (void) { hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.multihdmx.abc.ttf"); hb_face_t *face_a = hb_test_open_font_file ("fonts/Roboto-Regular.multihdmx.a.ttf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_abc_subset; hb_set_add (codepoints, 'a'); face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('h','d','m','x')); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); hb_face_destroy (face_a); }
/** * hb_ot_layout_get_size_params: * * Since: 0.9.10 **/ hb_bool_t hb_ot_layout_get_size_params (hb_face_t *face, unsigned int *design_size, /* OUT. May be NULL */ unsigned int *subfamily_id, /* OUT. May be NULL */ unsigned int *subfamily_name_id, /* OUT. May be NULL */ unsigned int *range_start, /* OUT. May be NULL */ unsigned int *range_end /* OUT. May be NULL */) { const OT::GPOS &gpos = _get_gpos (face); const hb_tag_t tag = HB_TAG ('s','i','z','e'); unsigned int num_features = gpos.get_feature_count (); for (unsigned int i = 0; i < num_features; i++) { if (tag == gpos.get_feature_tag (i)) { const OT::Feature &f = gpos.get_feature (i); const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); if (params.designSize) { #define PARAM(a, A) if (a) *a = params.A PARAM (design_size, designSize); PARAM (subfamily_id, subfamilyID); PARAM (subfamily_name_id, subfamilyNameID); PARAM (range_start, rangeStart); PARAM (range_end, rangeEnd); #undef PARAM return true; } } } #define PARAM(a, A) if (a) *a = 0 PARAM (design_size, designSize); PARAM (subfamily_id, subfamilyID); PARAM (subfamily_name_id, subfamilyNameID); PARAM (range_start, rangeStart); PARAM (range_end, rangeEnd); #undef PARAM return false; }
static void test_subset_hdmx_simple_subset (void) { hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_abc_subset; hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'c'); face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','d','m','x')); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); hb_face_destroy (face_ac); }
static void test_post_drops_glyph_names (void) { hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf"); hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E.ttf"); hb_face_t *face_full_subset; hb_set_t *codepoints = hb_set_create (); hb_set_add (codepoints, 0x660E); face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_subset, face_full_subset, HB_TAG ('p','o','s','t')); hb_face_destroy (face_full_subset); hb_face_destroy (face_full); hb_face_destroy (face_subset); }
static void test_subset_cff1_j (void) { hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf"); hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.otf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_41_3041_4c2e_subset; hb_set_add (codepoints, 0x41); hb_set_add (codepoints, 0x4C2E); face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_41_3041_4c2e_subset); hb_face_destroy (face_41_3041_4c2e); hb_face_destroy (face_41_4c2e); }
static void test_subset_cff1_expert (void) { hb_face_t *face = hb_test_open_font_file ("fonts/cff1_expert.otf"); hb_face_t *face_subset = hb_test_open_font_file ("fonts/cff1_expert.2D,F6E9,FB00.otf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_test; hb_set_add (codepoints, 0x2D); hb_set_add (codepoints, 0xF6E9); hb_set_add (codepoints, 0xFB00); face_test = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); hb_set_destroy (codepoints); hb_subset_test_check (face_subset, face_test, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_test); hb_face_destroy (face_subset); hb_face_destroy (face); }
void HarfBuzzShaper::setFontFeatures() { const FontDescription& description = m_font->fontDescription(); if (description.orientation() == Vertical) { static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) }; static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) }; m_features.append(vert); m_features.append(vrt2); } hb_feature_t kerning = { HarfBuzzFace::kernTag, 0, 0, static_cast<unsigned>(-1) }; switch (description.kerning()) { case FontDescription::NormalKerning: kerning.value = 1; m_features.append(kerning); break; case FontDescription::NoneKerning: kerning.value = 0; m_features.append(kerning); break; case FontDescription::AutoKerning: break; default: ASSERT_NOT_REACHED(); } FontFeatureSettings* settings = description.featureSettings(); if (!settings) return; unsigned numFeatures = settings->size(); for (unsigned i = 0; i < numFeatures; ++i) { hb_feature_t feature; auto& tag = settings->at(i).tag(); feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); feature.value = settings->at(i).value(); feature.start = 0; feature.end = static_cast<unsigned>(-1); m_features.append(feature); } }
static void test_subset_cff1_dotsection (void) { hb_face_t *face = hb_test_open_font_file ("fonts/cff1_dotsect.otf"); hb_face_t *face_subset = hb_test_open_font_file ("fonts/cff1_dotsect.nohints.otf"); hb_set_t *codepoints = hb_set_create (); hb_subset_input_t *input; hb_face_t *face_test; hb_set_add (codepoints, 0x69); /* i */ input = hb_subset_test_create_input (codepoints); hb_subset_input_set_drop_hints (input, true); face_test = hb_subset_test_create_subset (face, input); hb_set_destroy (codepoints); hb_subset_test_check (face_subset, face_test, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_test); hb_face_destroy (face_subset); hb_face_destroy (face); }
static void * data_create_use (const hb_ot_shape_plan_t *plan) { use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t)); if (unlikely (!use_plan)) return NULL; use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f')); if (has_arabic_joining (plan->props.script)) { use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan); if (unlikely (!use_plan->arabic_plan)) { free (use_plan); return NULL; } } return use_plan; }
static void test_subset_cff1_desubr (void) { hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf"); hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansPro-Regular.ac.nosubrs.otf"); hb_set_t *codepoints = hb_set_create (); hb_subset_input_t *input; hb_face_t *face_abc_subset; hb_set_add (codepoints, 'a'); hb_set_add (codepoints, 'c'); input = hb_subset_test_create_input (codepoints); hb_subset_input_set_desubroutinize (input, true); face_abc_subset = hb_subset_test_create_subset (face_abc, input); hb_set_destroy (codepoints); hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc); hb_face_destroy (face_ac); }
static void test_subset_cff1_j_desubr_strip_hints (void) { hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf"); hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.nosubrs.nohints.otf"); hb_set_t *codepoints = hb_set_create (); hb_face_t *face_41_3041_4c2e_subset; hb_subset_input_t *input; hb_set_add (codepoints, 0x41); hb_set_add (codepoints, 0x4C2E); input = hb_subset_test_create_input (codepoints); hb_subset_input_set_drop_hints (input, true); hb_subset_input_set_desubroutinize (input, true); face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input); hb_set_destroy (codepoints); hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' ')); hb_face_destroy (face_41_3041_4c2e_subset); hb_face_destroy (face_41_3041_4c2e); hb_face_destroy (face_41_4c2e); }
static void collect_features_use (hb_ot_shape_planner_t *plan) { hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); /* "Default glyph pre-processing group" */ map->add_global_bool_feature (HB_TAG('l','o','c','l')); map->add_global_bool_feature (HB_TAG('c','c','m','p')); map->add_global_bool_feature (HB_TAG('n','u','k','t')); map->add_global_bool_feature (HB_TAG('a','k','h','n')); /* "Reordering group" */ map->add_gsub_pause (clear_substitution_flags); map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ); map->add_gsub_pause (record_rphf); map->add_gsub_pause (clear_substitution_flags); map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ); map->add_gsub_pause (record_pref); /* "Orthographic unit shaping group" */ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); map->add_gsub_pause (reorder); /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) map->add_feature (arabic_features[i], 1, F_NONE); map->add_gsub_pause (NULL); /* "Standard typographic presentation" and "Positional feature application" */ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); }
void HarfBuzzShaper::setFontFeatures() { const FontDescription& description = m_font->getFontDescription(); static hb_feature_t noKern = createFeature('k', 'e', 'r', 'n'); static hb_feature_t noVkrn = createFeature('v', 'k', 'r', 'n'); switch (description.getKerning()) { case FontDescription::NormalKerning: // kern/vkrn are enabled by default break; case FontDescription::NoneKerning: m_features.append(description.isVerticalAnyUpright() ? noVkrn : noKern); break; case FontDescription::AutoKerning: break; } static hb_feature_t noClig = createFeature('c', 'l', 'i', 'g'); static hb_feature_t noLiga = createFeature('l', 'i', 'g', 'a'); switch (description.commonLigaturesState()) { case FontDescription::DisabledLigaturesState: m_features.append(noLiga); m_features.append(noClig); break; case FontDescription::EnabledLigaturesState: // liga and clig are on by default break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t dlig = createFeature('d', 'l', 'i', 'g', 1); switch (description.discretionaryLigaturesState()) { case FontDescription::DisabledLigaturesState: // dlig is off by default break; case FontDescription::EnabledLigaturesState: m_features.append(dlig); break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t hlig = createFeature('h', 'l', 'i', 'g', 1); switch (description.historicalLigaturesState()) { case FontDescription::DisabledLigaturesState: // hlig is off by default break; case FontDescription::EnabledLigaturesState: m_features.append(hlig); break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t noCalt = createFeature('c', 'a', 'l', 't'); switch (description.contextualLigaturesState()) { case FontDescription::DisabledLigaturesState: m_features.append(noCalt); break; case FontDescription::EnabledLigaturesState: // calt is on by default break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t hwid = createFeature('h', 'w', 'i', 'd', 1); static hb_feature_t twid = createFeature('t', 'w', 'i', 'd', 1); static hb_feature_t qwid = createFeature('q', 'w', 'i', 'd', 1); switch (description.widthVariant()) { case HalfWidth: m_features.append(hwid); break; case ThirdWidth: m_features.append(twid); break; case QuarterWidth: m_features.append(qwid); break; case RegularWidth: break; } FontFeatureSettings* settings = description.featureSettings(); if (!settings) return; unsigned numFeatures = settings->size(); for (unsigned i = 0; i < numFeatures; ++i) { hb_feature_t feature; const AtomicString& tag = settings->at(i).tag(); feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); feature.value = settings->at(i).value(); feature.start = 0; feature.end = static_cast<unsigned>(-1); m_features.append(feature); } }
unsigned int j_type = joining_type(u); if (likely (j_type != JOINING_TYPE_X)) return j_type; return (FLAG_SAFE(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT)) ) ? JOINING_TYPE_T : JOINING_TYPE_U; } #define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3') static const hb_tag_t arabic_features[] = { HB_TAG('i','s','o','l'), HB_TAG('f','i','n','a'), HB_TAG('f','i','n','2'), HB_TAG('f','i','n','3'), HB_TAG('m','e','d','i'), HB_TAG('m','e','d','2'), HB_TAG('i','n','i','t'), HB_TAG_NONE }; /* Same order as the feature array */ enum arabic_action_t { ISOL, FINA, FIN2,
/* Same order as the feature array below */ enum { NONE, LJMO, VJMO, TJMO, FIRST_HANGUL_FEATURE = LJMO, HANGUL_FEATURE_COUNT = TJMO + 1 }; static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] = { HB_TAG_NONE, HB_TAG('l','j','m','o'), HB_TAG('v','j','m','o'), HB_TAG('t','j','m','o') }; static void collect_features_hangul (hb_ot_shape_planner_t *plan) { hb_ot_map_builder_t *map = &plan->map; for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++) map->add_feature (hangul_features[i], 1, F_NONE); } static void override_features_hangul (hb_ot_shape_planner_t *plan)
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; }
void HarfBuzzShaper::setFontFeatures() { const FontDescription& description = m_font->getFontDescription(); static hb_feature_t noKern = createFeature('k', 'e', 'r', 'n'); static hb_feature_t noVkrn = createFeature('v', 'k', 'r', 'n'); switch (description.getKerning()) { case FontDescription::NormalKerning: // kern/vkrn are enabled by default break; case FontDescription::NoneKerning: m_features.append(description.isVerticalAnyUpright() ? noVkrn : noKern); break; case FontDescription::AutoKerning: break; } static hb_feature_t noClig = createFeature('c', 'l', 'i', 'g'); static hb_feature_t noLiga = createFeature('l', 'i', 'g', 'a'); switch (description.commonLigaturesState()) { case FontDescription::DisabledLigaturesState: m_features.append(noLiga); m_features.append(noClig); break; case FontDescription::EnabledLigaturesState: // liga and clig are on by default break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t dlig = createFeature('d', 'l', 'i', 'g', 1); switch (description.discretionaryLigaturesState()) { case FontDescription::DisabledLigaturesState: // dlig is off by default break; case FontDescription::EnabledLigaturesState: m_features.append(dlig); break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t hlig = createFeature('h', 'l', 'i', 'g', 1); switch (description.historicalLigaturesState()) { case FontDescription::DisabledLigaturesState: // hlig is off by default break; case FontDescription::EnabledLigaturesState: m_features.append(hlig); break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t noCalt = createFeature('c', 'a', 'l', 't'); switch (description.contextualLigaturesState()) { case FontDescription::DisabledLigaturesState: m_features.append(noCalt); break; case FontDescription::EnabledLigaturesState: // calt is on by default break; case FontDescription::NormalLigaturesState: break; } static hb_feature_t hwid = createFeature('h', 'w', 'i', 'd', 1); static hb_feature_t twid = createFeature('t', 'w', 'i', 'd', 1); static hb_feature_t qwid = createFeature('q', 'w', 'i', 'd', 1); switch (description.widthVariant()) { case HalfWidth: m_features.append(hwid); break; case ThirdWidth: m_features.append(twid); break; case QuarterWidth: m_features.append(qwid); break; case RegularWidth: break; } // font-variant-numeric: static hb_feature_t lnum = createFeature('l', 'n', 'u', 'm', 1); if (description.variantNumeric().numericFigureValue() == FontVariantNumeric::LiningNums) m_features.append(lnum); static hb_feature_t onum = createFeature('o', 'n', 'u', 'm', 1); if (description.variantNumeric().numericFigureValue() == FontVariantNumeric::OldstyleNums) m_features.append(onum); static hb_feature_t pnum = createFeature('p', 'n', 'u', 'm', 1); if (description.variantNumeric().numericSpacingValue() == FontVariantNumeric::ProportionalNums) m_features.append(pnum); static hb_feature_t tnum = createFeature('t', 'n', 'u', 'm', 1); if (description.variantNumeric().numericSpacingValue() == FontVariantNumeric::TabularNums) m_features.append(tnum); static hb_feature_t afrc = createFeature('a', 'f', 'r', 'c', 1); if (description.variantNumeric().numericFractionValue() == FontVariantNumeric::StackedFractions) m_features.append(afrc); static hb_feature_t frac = createFeature('f', 'r', 'a', 'c', 1); if (description.variantNumeric().numericFractionValue() == FontVariantNumeric::DiagonalFractions) m_features.append(frac); static hb_feature_t ordn = createFeature('o', 'r', 'd', 'n', 1); if (description.variantNumeric().ordinalValue() == FontVariantNumeric::OrdinalOn) m_features.append(ordn); static hb_feature_t zero = createFeature('z', 'e', 'r', 'o', 1); if (description.variantNumeric().slashedZeroValue() == FontVariantNumeric::SlashedZeroOn) m_features.append(zero); FontFeatureSettings* settings = description.featureSettings(); if (!settings) return; // TODO(drott): crbug.com/450619 Implement feature resolution instead of // just appending the font-feature-settings. unsigned numFeatures = settings->size(); for (unsigned i = 0; i < numFeatures; ++i) { hb_feature_t feature; const AtomicString& tag = settings->at(i).tag(); feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); feature.value = settings->at(i).value(); feature.start = 0; feature.end = static_cast<unsigned>(-1); m_features.append(feature); } }
#define use_category() complex_var_u8_0() /* * Universal Shaping Engine. * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm */ static const hb_tag_t basic_features[] = { /* * Basic features. * These features are applied all at once, before reordering. */ HB_TAG('r','k','r','f'), HB_TAG('a','b','v','f'), HB_TAG('b','l','w','f'), HB_TAG('h','a','l','f'), HB_TAG('p','s','t','f'), HB_TAG('v','a','t','u'), HB_TAG('c','j','c','t'), }; static const hb_tag_t arabic_features[] = { HB_TAG('i','s','o','l'), HB_TAG('i','n','i','t'), HB_TAG('m','e','d','i'), HB_TAG('f','i','n','a'), /* The spec doesn't specify these but we apply anyway, since our Arabic shaper