applyRulesToInlineStyle function

String applyRulesToInlineStyle(
  1. String? inlineStyle,
  2. Iterable<CssStyleRule> rules
)

Merges the winning declarations of rules into inlineStyle.

rules is the set of rules one element matches. Every rule in it is treated as matching; the caller has already decided that. The cascade is resolved here, per property, in this order, strongest first:

  1. an !important declaration in the inline style,
  2. an !important declaration in a stylesheet,
  3. a normal declaration in the inline style,
  4. a normal declaration in a stylesheet.

Inside one tier the higher CssStyleRule.specificity wins, and a tie goes to the higher CssStyleRule.order.

The result keeps the inline style verbatim in the middle. A stylesheet declaration that loses to the inline style is written before it, and one that wins is written after it, because flutter_html gives the last declaration of a property the win. The !important flag is not written out: the cascade is already resolved, and several sibling extensions read the inline style with a parser of their own.

Returns inlineStyle unchanged when no rule contributes anything.

Implementation

String applyRulesToInlineStyle(
  String? inlineStyle,
  Iterable<CssStyleRule> rules,
) {
  final inline = (inlineStyle ?? '').trim();
  final inlineTiers = <String, bool>{};
  for (final declaration in parseDeclarationList(inline)) {
    // A later inline declaration of the same property wins, so the last flag
    // read is the one that counts.
    inlineTiers[declaration.property] = declaration.important;
  }

  final winners = <String, _Winner>{};
  for (final rule in rules) {
    for (final declaration in rule.declarations) {
      final candidate = _Winner(declaration, rule);
      final standing = winners[declaration.property];
      if (standing == null || candidate.beats(standing)) {
        winners[declaration.property] = candidate;
      }
    }
  }
  if (winners.isEmpty) return inlineStyle ?? '';

  final before = <StylesheetDeclaration>[];
  final after = <StylesheetDeclaration>[];
  final ordered = winners.values.toList()
    ..sort((a, b) => a.rule.order.compareTo(b.rule.order));

  for (final winner in ordered) {
    final property = winner.declaration.property;
    final inlineImportant = inlineTiers[property];
    final written = StylesheetDeclaration(property, winner.declaration.value);
    if (inlineImportant == null) {
      before.add(written);
    } else if (winner.declaration.important && !inlineImportant) {
      after.add(written);
    } else {
      // The inline declaration wins. Writing the loser out anyway keeps the
      // element's computed value visible to a sibling extension that reads
      // only the first declaration of a property.
      before.add(written);
    }
  }

  final parts = <String>[
    if (before.isNotEmpty) joinDeclarationList(before),
    if (inline.isNotEmpty) _withoutTrailingSemicolon(inline),
    if (after.isNotEmpty) joinDeclarationList(after),
  ];
  return parts.join('; ');
}