supportsFontFeature static method

bool supportsFontFeature(
  1. CSSRenderStyle renderStyle,
  2. String tag
)

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