supportsFontFeature static method
Implementation
static bool supportsFontFeature(CSSRenderStyle renderStyle, String tag) {
final List<String>? families = renderStyle.fontFamily;
final String primary = (families != null && families.isNotEmpty) ? families.first : '';
final FontWeight effectiveWeight = CSSTextMixin._effectiveFontWeight(renderStyle);
final _FontFeatureSupportKey key = _FontFeatureSupportKey(
primaryFamily: primary,
weightIndex: effectiveWeight.index,
fontStyle: renderStyle.fontStyle,
tag: tag,
);
final bool? cached = _featureSupportCache[key];
if (cached != null) return cached;
// Ensure primary font is requested before probing.
if (primary.isNotEmpty) {
CSSFontFace.ensureFontLoaded(primary, effectiveWeight, renderStyle);
}
// Probe by measuring if enabling a feature changes layout metrics; when the
// font doesn't support it, metrics should remain identical (heuristic).
Size measure(String text, {List<FontFeature>? features}) {
final TextPainter tp = TextPainter(
text: TextSpan(
text: text,
style: TextStyle(
fontFamily: primary.isNotEmpty ? primary : null,
fontFamilyFallback: families,
fontWeight: effectiveWeight,
fontStyle: renderStyle.fontStyle,
fontSize: math.max(0.0, renderStyle.fontSize.computedValue),
fontFeatures: features,
),
),
textScaler: renderStyle.textScaler,
textDirection: TextDirection.ltr,
)..layout();
return tp.size;
}
const samples = ['a', 'abcxyz', 'mixedCapsAa'];
bool supported = false;
for (final s in samples) {
final Size base = measure(s);
final Size feat = measure(s, features: [FontFeature.enable(tag)]);
final double dw = (feat.width - base.width).abs();
final double dh = (feat.height - base.height).abs();
if (dw > 0.1 || dh > 0.1) {
supported = true;
break;
}
}
_featureSupportCache[key] = supported;
return supported;
}