setInlineStyle method

void setInlineStyle(
  1. String property,
  2. String value, {
  3. String? baseHref,
  4. bool fromNative = false,
  5. bool important = false,
  6. bool validate = true,
})

Implementation

void setInlineStyle(String property, String value,
    {String? baseHref, bool fromNative = false, bool important = false, bool validate = true}) {
  property = CSSStyleDeclaration.normalizePropertyName(property);
  final bool enableBlink = ownerDocument.ownerView.enableBlink;
  // Whether to validate inline style values in Dart. In Blink mode, legacy
  // CSSOM inline style updates are validated on the Dart side to preserve
  // CSSOM semantics (invalid values should be ignored).
  final bool validateInline = validate;
  // Sheet styles pushed from native Blink are already validated; avoid
  // re-validating them on the Dart side.
  final bool validateSheet = !(fromNative && enableBlink);
  final InlineStyleEntry? previousEntry = inlineStyle[property];

  bool derivedImportant = important;
  String derivedValue = value;

  // Legacy native bridge encodes CSSOM priority by appending `!important`
  // into the value string (for older versions where UICommandType.setInlineStyle
  // doesn't carry a priority field). Decode it back to the structured `important` flag so
  // Dart-side parsing/cascade works as expected.
  if (fromNative && !derivedImportant) {
    int end = derivedValue.length;
    while (end > 0 && derivedValue.codeUnitAt(end - 1) <= 0x20) {
      end--;
    }

    const String keyword = 'important';
    if (end >= keyword.length) {
      final int keywordStart = end - keyword.length;
      if (derivedValue.substring(keywordStart, end).toLowerCase() == keyword) {
        int i = keywordStart;
        while (i > 0 && derivedValue.codeUnitAt(i - 1) <= 0x20) {
          i--;
        }
        if (i > 0 && derivedValue.codeUnitAt(i - 1) == 0x21) {
          derivedImportant = true;
          derivedValue = derivedValue.substring(0, i - 1).trimRight();
        }
      }
    }
  }

  InlineStyleEntry entry =
      InlineStyleEntry(derivedValue, important: derivedImportant);
  if (fromNative && !derivedImportant) {
    entry = _normalizeInlineStyleEntryFromNative(entry);
  }

  // recalculate matching styles for element when inline styles are removed.
  if (entry.value.isEmpty) {
    inlineStyle.remove(property);
    final bool? wasImportant =
        (previousEntry?.important ?? entry.important) ? true : null;
    style.removeProperty(property, wasImportant);
    if (fromNative && enableBlink) {
      final CSSStyleDeclaration? sheetStyle = _sheetStyle;
      if (sheetStyle != null) {
        final String sheetValue = sheetStyle.getPropertyValue(property);
        if (sheetValue.isNotEmpty) {
          style.enqueueSheetProperty(
            property,
            sheetValue,
            isImportant: sheetStyle.isImportant(property) ? true : null,
            baseHref: sheetStyle.getPropertyBaseHref(property),
            validate: validateSheet,
          );
        }
      }
    }
    // When Blink CSS is enabled, non-inline cascading happens on the native
    // side. Avoid expensive Dart-side full recalculation here.
    if (!(fromNative && enableBlink)) {
      recalculateStyle();
    }
    return;
  } else {
    if (validateInline) {
      final String v = entry.value.trim();
      // Ensure invalid `gap` values don't overwrite previous valid values.
      // This is particularly important in Blink mode where inline CSSOM
      // updates are forwarded from native without native-side validation.
      if (property == GAP || property == ROW_GAP || property == COLUMN_GAP) {
        if (property == GAP) {
          final List<String> parts = splitByTopLevelDelimiter(v, 0x20 /* space */)
              .map((p) => p.trim())
              .where((p) => p.isNotEmpty)
              .toList();
          if (parts.isEmpty || parts.length > 2) return;
          for (final String part in parts) {
            if (!CSSGap.isValidGapValue(part)) return;
          }
        } else {
          if (!CSSGap.isValidGapValue(v)) return;
        }
      }
    }
    // Current only for mark property is setting by inline style.
    inlineStyle[property] = entry;
    if (previousEntry?.important == true && !entry.important) {
      style.removeProperty(property, true);
    }
    style.enqueueInlineProperty(property, entry.value,
        isImportant: entry.important ? true : null, baseHref: baseHref, validate: validateInline);
  }
}