2

I would like to disable ligatures, which appear to be enabled by default, at least in the fonts that I'm using (i.e. Calibri). It appears that the way to do this is to use IDWriteTextLayout::SetTypography to set an IDWriteTypography object to the layout which contains the various ligature-related font features with a value of zero to disable them. That works to disable the ligatures, but it also affects (disables) other typography settings that I don't want to mess with, such as kerning.

After some experimentation, it turns out that I could disable ligatures just by setting an empty IDWriteTypography object (one that was simply created by the IDWriteFactory and then applied to the layout without alteration). An empty typography seems to have the effect of setting all possible font features to zero/disable. So what I actually want to do is retrieve the default typography settings, override the ones related to ligatures, and then set that to the layout.

Unfortunately I can't find anywhere to retrieve the default settings. Using IDWriteTextLayout::GetTypography just returns null if none has been set, yet it clearly has various typography settings like ligatures enabled in that case. I also can't find any other methods on IDWriteFactory (or any of its newer versions) or any of the font-related interfaces for creating an IDWriteTypography instance. How does the IDWriteTextLayout decide which typography settings to use when no IDWriteTypography has been set? Are the default settings font-specific? Can I retrieve those settings somehow so that I can tweak a few of them and inherit the default values for the rest?

4

2 回答 2

3

There's no way to get default set of features out of IDWriteTextLayout, or IDWriteTextAnalyzer to be more precise, and no, it's not font-specific, it's script-specific.

If you're interested in how it works in general, you can use opensource implementations like HarfBuzz, you can find arrays of script-specific features that are applied during shaping.

Microsoft approach to that is documented in OpenType documentation, an example for Arabic - https://www.microsoft.com/typography/OpenTypeDev/arabic/intro.htm.

于 2016-01-07T17:06:12.870 回答
1

It appears that the way to do this is to use IDWriteTextLayout::SetTypography

As early as of Sep 13, 2015 (the date of your asking this question) you WERE ABLE to disable ligatures, in particular, for a Calibri font, WITHOUT messing with a IDWriteTypography object and its default settings.

You may be were unable to disable ligatures "globally" in the way you liked, but you always do have an option to disable ligatures when you actually extract glyphs for a piece of text in your code. The 9th, 10th, and 11th ('features', 'featureLengths', and 'featureCount') parameters of an IDWriteTextAnalyzer::GetGlyph(...) method are to your help.

For example, to disable ligatures, you write in your code (I borrowed this piece from a FLowLayout::ShapeGlyphRun method of the Windows7 SDK CustomLayout sample and added some feature params initializations; initially, the 9th to 11th parameter values were NULL, NULL, 0):

    DWRITE_FONT_FEATURE fontFeature = { DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES, 0 };

    const DWRITE_TYPOGRAPHIC_FEATURES* typoFeatures = 
        new DWRITE_TYPOGRAPHIC_FEATURES{ { &fontFeature } };

    UINT32 featureLengths[1];

    featureLengths[0] = textLength;

    hr = textAnalyzer->GetGlyphs(
            &text_[textStart],
            textLength,
            fontFace_,
            run.isSideways,         // isSideways,
            (run.bidiLevel & 1),    // isRightToLeft
            &run.script,
            localeName_,
            (run.isNumberSubstituted) ? numberSubstitution_ : NULL,
            &typoFeatures,                   // features
            featureLengths,                   // featureLengths
            1,                      // featureCount
            maxGlyphCount,          // maxGlyphCount
            &glyphClusters_[textStart],
            &textProps[0],
            &glyphIndices_[glyphStart],
            &glyphProps[0],
            &actualGlyphCount
            );

    delete typoFeatures;

A second parameter (0) in the fontFeature initializer DISABLES use of ligatures for a text range {textStart, textStart + textLength}, whatever ligature-enabled font you use in this text range. A non-zero parameter value would enable this feature, but this feature, as you know, is enabled by default.

For the next piece of text (starting at textStart + textLength and further on) you can re-use your initialized feature values in order to continue disable ligatures; but, if you return to NULL, NULL, 0 values of GetGlyph's 9th to 11th feature params, ligatures for this latter text range are enabled without use of explicit feature settings in GetGlyph.

See reference: https://msdn.microsoft.com/en-us/library/windows/desktop/dd316625(v=vs.85).aspx .

As of now, a new DirectWrite text engine might be offering more convenient ways to control use of typographic/font features -- I cannot tell you for sure, but the above info might be helpful for those writing code compatible with Windows 7.

于 2018-02-15T06:11:43.223 回答