applyRulesToInlineStyle function
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:
- an
!importantdeclaration in the inline style, - an
!importantdeclaration in a stylesheet, - a normal declaration in the inline style,
- 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('; ');
}