Commit bae4d924 authored by John Daggett's avatar John Daggett
Browse files

Bug 718539. Merge per-font and style rule font features. r=jkew

parent 04c2cd9e
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -1350,6 +1350,48 @@ gfxFontCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
    SizeOfExcludingThis(aMallocSizeOf, aSizes);
}

/* static */ bool
gfxFontShaper::MergeFontFeatures(
    const nsTArray<gfxFontFeature>& aStyleRuleFeatures,
    const nsTArray<gfxFontFeature>& aFontFeatures,
    bool aDisableLigatures,
    nsDataHashtable<nsUint32HashKey,PRUint32>& aMergedFeatures)
{
    // bail immediately if nothing to do
    if (aStyleRuleFeatures.IsEmpty() &&
        aFontFeatures.IsEmpty() &&
        !aDisableLigatures) {
        return false;
    }

    aMergedFeatures.Init();

    // Ligature features are enabled by default in the generic shaper,
    // so we explicitly turn them off if necessary (for letter-spacing)
    if (aDisableLigatures) {
        aMergedFeatures.Put(HB_TAG('l','i','g','a'), 0);
        aMergedFeatures.Put(HB_TAG('c','l','i','g'), 0);
    }

    // add feature values from font
    PRUint32 i, count;

    count = aFontFeatures.Length();
    for (i = 0; i < count; i++) {
        const gfxFontFeature& feature = aFontFeatures.ElementAt(i);
        aMergedFeatures.Put(feature.mTag, feature.mValue);
    }

    // add feature values from style rules
    count = aStyleRuleFeatures.Length();
    for (i = 0; i < count; i++) {
        const gfxFontFeature& feature = aStyleRuleFeatures.ElementAt(i);
        aMergedFeatures.Put(feature.mTag, feature.mValue);
    }

    return aMergedFeatures.Count() != 0;
}

void
gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft)
{
+7 −0
Original line number Diff line number Diff line
@@ -1154,6 +1154,13 @@ public:

    gfxFont *GetFont() const { return mFont; }

    // returns true if features exist in output, false otherwise
    static bool
    MergeFontFeatures(const nsTArray<gfxFontFeature>& aStyleRuleFeatures,
                      const nsTArray<gfxFontFeature>& aFontFeatures,
                      bool aDisableLigatures,
                      nsDataHashtable<nsUint32HashKey,PRUint32>& aMergedFeatures);

protected:
    // the font this shaper is working with
    gfxFont * mFont;
+26 −20
Original line number Diff line number Diff line
@@ -154,6 +154,23 @@ MakeGraphiteLangTag(PRUint32 aTag)
    return grLangTag;
}

struct GrFontFeatures {
    gr_face        *mFace;
    gr_feature_val *mFeatures;
};

static PLDHashOperator
AddFeature(const PRUint32& aTag, PRUint32& aValue, void *aUserArg)
{
    GrFontFeatures *f = static_cast<GrFontFeatures*>(aUserArg);

    const gr_feature_ref* fref = gr_face_find_fref(f->mFace, aTag);
    if (fref) {
        gr_fref_set_feature_value(fref, aValue, f->mFeatures);
    }
    return PL_DHASH_NEXT;
}

bool
gfxGraphiteShaper::ShapeWord(gfxContext      *aContext,
                             gfxShapedWord   *aShapedWord,
@@ -197,32 +214,21 @@ gfxGraphiteShaper::ShapeWord(gfxContext *aContext,
    }
    gr_feature_val *grFeatures = gr_face_featureval_for_lang(mGrFace, grLang);

    if (aShapedWord->DisableLigatures()) {
        const gr_feature_ref* fref =
            gr_face_find_fref(mGrFace, TRUETYPE_TAG('l','i','g','a'));
        if (fref) {
            gr_fref_set_feature_value(fref, 0, grFeatures);
        }
    }
    nsDataHashtable<nsUint32HashKey,PRUint32> mergedFeatures;

    const nsTArray<gfxFontFeature> *features = &style->featureSettings;
    if (features->IsEmpty()) {
        features = &entry->mFeatureSettings;
    }
    for (PRUint32 i = 0; i < features->Length(); ++i) {
        const gr_feature_ref* fref =
            gr_face_find_fref(mGrFace, (*features)[i].mTag);
        if (fref) {
            gr_fref_set_feature_value(fref, (*features)[i].mValue, grFeatures);
        }
    if (MergeFontFeatures(style->featureSettings, entry->mFeatureSettings,
                          aShapedWord->DisableLigatures(), mergedFeatures)) {
        // enumerate result and insert into Graphite feature list
        GrFontFeatures f = {mGrFace, grFeatures};
        mergedFeatures.Enumerate(AddFeature, &f);
    }

    gr_segment *seg = gr_make_seg(mGrFont, mGrFace, 0, grFeatures,
                                  gr_utf16, aText, aShapedWord->Length(),
                                  aShapedWord->IsRightToLeft());
    if (features) {

    gr_featureval_destroy(grFeatures);
    }

    if (!seg) {
        return false;
    }
+20 −27
Original line number Diff line number Diff line
@@ -842,6 +842,18 @@ HBUnicodeDecompose(hb_unicode_funcs_t *ufuncs,
    return nsUnicodeNormalizer::DecomposeNonRecursively(ab, a, b);
}

static PLDHashOperator
AddFeature(const PRUint32& aTag, PRUint32& aValue, void *aUserArg)
{
    nsTArray<hb_feature_t>* features = static_cast<nsTArray<hb_feature_t>*> (aUserArg);

    hb_feature_t feat = { 0, 0, 0, UINT_MAX };
    feat.tag = aTag;
    feat.value = aValue;
    features->AppendElement(feat);
    return PL_DHASH_NEXT;
}

/*
 * gfxFontShaper override to initialize the text run using HarfBuzz
 */
@@ -973,35 +985,16 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,

    nsAutoTArray<hb_feature_t,20> features;

    // Ligature features are enabled by default in the generic shaper,
    // so we explicitly turn them off if necessary (for letter-spacing)
    if (aShapedWord->DisableLigatures()) {
        hb_feature_t ligaOff = { HB_TAG('l','i','g','a'), 0, 0, UINT_MAX };
        hb_feature_t cligOff = { HB_TAG('c','l','i','g'), 0, 0, UINT_MAX };
        features.AppendElement(ligaOff);
        features.AppendElement(cligOff);
    }

    // css features need to be merged with the existing ones, if any
    gfxFontEntry *entry = mFont->GetFontEntry();
    const gfxFontStyle *style = mFont->GetStyle();
    const nsTArray<gfxFontFeature> *cssFeatures = &style->featureSettings;
    if (cssFeatures->IsEmpty()) {
        cssFeatures = &entry->mFeatureSettings;
    }
    for (PRUint32 i = 0; i < cssFeatures->Length(); ++i) {
        PRUint32 j;
        for (j = 0; j < features.Length(); ++j) {
            if (cssFeatures->ElementAt(i).mTag == features[j].tag) {
                features[j].value = cssFeatures->ElementAt(i).mValue;
                break;
            }
        }
        if (j == features.Length()) {
            const gfxFontFeature& f = cssFeatures->ElementAt(i);
            hb_feature_t hbf = { f.mTag, f.mValue, 0, UINT_MAX };
            features.AppendElement(hbf);
        }

    nsDataHashtable<nsUint32HashKey,PRUint32> mergedFeatures;

    if (MergeFontFeatures(style->featureSettings,
                      mFont->GetFontEntry()->mFeatureSettings,
                      aShapedWord->DisableLigatures(), mergedFeatures)) {
        // enumerate result and insert into hb_feature array
        mergedFeatures.Enumerate(AddFeature, &features);
    }

    bool isRightToLeft = aShapedWord->IsRightToLeft();