resolveValue method

  1. @override
dynamic resolveValue(
  1. String propertyName,
  2. String propertyValue, {
  3. String? baseHref,
})
override

Resolve the style value.

Implementation

@override
dynamic resolveValue(String propertyName, String propertyValue, {String? baseHref}) {
  RenderStyle renderStyle = this;

  // For CSS custom properties (variables), do not attempt to interpret
  // or coerce values. Preserve the raw string verbatim so comma-separated
  // lists like "var(--a), var(--b)" are stored intact.
  if (CSSVariable.isCSSSVariableProperty(propertyName)) {
    return propertyValue;
  }

  // Map logical properties to physical properties based on current direction
  String mappedPropertyName = propertyName;
  final bool isRTL = direction == TextDirection.rtl;

  // Handle inline-start properties (maps to left in LTR, right in RTL)
  if (propertyName == MARGIN_INLINE_START) {
    mappedPropertyName = isRTL ? MARGIN_RIGHT : MARGIN_LEFT;
  } else if (propertyName == PADDING_INLINE_START) {
    mappedPropertyName = isRTL ? PADDING_RIGHT : PADDING_LEFT;
  } else if (propertyName == BORDER_INLINE_START) {
    mappedPropertyName = isRTL ? BORDER_RIGHT : BORDER_LEFT;
  } else if (propertyName == BORDER_INLINE_START_WIDTH) {
    mappedPropertyName = isRTL ? BORDER_RIGHT_WIDTH : BORDER_LEFT_WIDTH;
  } else if (propertyName == BORDER_INLINE_START_STYLE) {
    mappedPropertyName = isRTL ? BORDER_RIGHT_STYLE : BORDER_LEFT_STYLE;
  } else if (propertyName == BORDER_INLINE_START_COLOR) {
    mappedPropertyName = isRTL ? BORDER_RIGHT_COLOR : BORDER_LEFT_COLOR;
  } else if (propertyName == INSET_INLINE_START) {
    mappedPropertyName = isRTL ? RIGHT : LEFT;
  }
  // Handle inline-end properties (maps to right in LTR, left in RTL)
  else if (propertyName == MARGIN_INLINE_END) {
    mappedPropertyName = isRTL ? MARGIN_LEFT : MARGIN_RIGHT;
  } else if (propertyName == PADDING_INLINE_END) {
    mappedPropertyName = isRTL ? PADDING_LEFT : PADDING_RIGHT;
  } else if (propertyName == BORDER_INLINE_END) {
    mappedPropertyName = isRTL ? BORDER_LEFT : BORDER_RIGHT;
  } else if (propertyName == BORDER_INLINE_END_WIDTH) {
    mappedPropertyName = isRTL ? BORDER_LEFT_WIDTH : BORDER_RIGHT_WIDTH;
  } else if (propertyName == BORDER_INLINE_END_STYLE) {
    mappedPropertyName = isRTL ? BORDER_LEFT_STYLE : BORDER_RIGHT_STYLE;
  } else if (propertyName == BORDER_INLINE_END_COLOR) {
    mappedPropertyName = isRTL ? BORDER_LEFT_COLOR : BORDER_RIGHT_COLOR;
  } else if (propertyName == INSET_INLINE_END) {
    mappedPropertyName = isRTL ? LEFT : RIGHT;
  }
  // Handle block-start properties (maps to top)
  else if (propertyName == MARGIN_BLOCK_START) {
    mappedPropertyName = MARGIN_TOP;
  } else if (propertyName == PADDING_BLOCK_START) {
    mappedPropertyName = PADDING_TOP;
  } else if (propertyName == BORDER_BLOCK_START) {
    mappedPropertyName = BORDER_TOP;
  } else if (propertyName == BORDER_BLOCK_START_WIDTH) {
    mappedPropertyName = BORDER_TOP_WIDTH;
  } else if (propertyName == BORDER_BLOCK_START_STYLE) {
    mappedPropertyName = BORDER_TOP_STYLE;
  } else if (propertyName == BORDER_BLOCK_START_COLOR) {
    mappedPropertyName = BORDER_TOP_COLOR;
  } else if (propertyName == INSET_BLOCK_START) {
    mappedPropertyName = TOP;
  }
  // Handle block-end properties (maps to bottom)
  else if (propertyName == MARGIN_BLOCK_END) {
    mappedPropertyName = MARGIN_BOTTOM;
  } else if (propertyName == PADDING_BLOCK_END) {
    mappedPropertyName = PADDING_BOTTOM;
  } else if (propertyName == BORDER_BLOCK_END) {
    mappedPropertyName = BORDER_BOTTOM;
  } else if (propertyName == BORDER_BLOCK_END_WIDTH) {
    mappedPropertyName = BORDER_BOTTOM_WIDTH;
  } else if (propertyName == BORDER_BLOCK_END_STYLE) {
    mappedPropertyName = BORDER_BOTTOM_STYLE;
  } else if (propertyName == BORDER_BLOCK_END_COLOR) {
    mappedPropertyName = BORDER_BOTTOM_COLOR;
  } else if (propertyName == INSET_BLOCK_END) {
    mappedPropertyName = BOTTOM;
  }

  // Use the mapped property name for further processing
  propertyName = mappedPropertyName;

  if (propertyValue == INITIAL) {
    propertyValue = CSSInitialValues[propertyName] ?? propertyValue;
  }

  // Process CSSVariable only when the entire value is a single var(...)
  // wrapper. For mixed tokens (e.g., 'var(--a) solid var(--b)'), do not
  // return a CSSVariable here; instead expand inline below and parse.
  if (CSSWritingModeMixin._isEntireVarFunction(propertyValue)) {
    dynamic value = CSSVariable.tryParse(renderStyle, propertyValue);
    if (value != null) {

      return value;
    }
  }

  // Expand inline var(...) occurrences embedded within a value string (e.g.,
  // 'red var(--b)') so property-specific parsers see fully-resolved tokens.
  // If a referenced variable cannot be resolved (and has no fallback), the
  // var(...) is left intact so the property parser fails and the property
  // becomes invalid at computed-value time per spec (inherited or initial).
  if (propertyValue.contains('var(')) {
    propertyValue = CSSWritingModeMixin.expandInlineVars(propertyValue, renderStyle, propertyName);
  }

  dynamic value;
  switch (propertyName) {
    case DISPLAY:
      value = CSSDisplayMixin.resolveDisplay(propertyValue);
      break;
    case OVERFLOW_X:
    case OVERFLOW_Y:
      value = CSSOverflowMixin.resolveOverflowType(propertyValue);
      break;
    case POSITION:
      value = CSSPositionMixin.resolvePositionType(propertyValue);
      break;
    case Z_INDEX:
      value = int.tryParse(propertyValue);
      break;
    case TOP:
    case LEFT:
    case BOTTOM:
    case RIGHT:
    case FLEX_BASIS:
    case WIDTH:
    case MIN_WIDTH:
    case MAX_WIDTH:
    case HEIGHT:
    case MIN_HEIGHT:
    case MAX_HEIGHT:
    case X:
    case Y:
    case RX:
    case RY:
    case CX:
    case CY:
    case R:
    case X1:
    case X2:
    case Y1:
    case Y2:
    case STROKE_WIDTH:
      value = CSSLength.resolveLength(propertyValue, renderStyle, propertyName);
      break;
    case ASPECT_RATIO:
      value = CSSSizingMixin.resolveAspectRatio(propertyValue);
      break;
    case GAP:
    case ROW_GAP:
    case COLUMN_GAP:
      value = CSSGapMixin.resolveGap(propertyValue, renderStyle: renderStyle);
      break;
    case PADDING_TOP:
    case MARGIN_TOP:
      List<String?>? values = CSSStyleProperty.getEdgeValues(propertyValue);
      if (values != null && values[0] != null) {
        value = CSSLength.resolveLength(values[0]!, renderStyle, propertyName);
      } else {
        value = CSSLength.resolveLength(propertyValue, renderStyle, propertyName);
      }
      break;
    case MARGIN_RIGHT:
    case PADDING_RIGHT:
      List<String?>? values = CSSStyleProperty.getEdgeValues(propertyValue);
      if (values != null && values[1] != null) {
        value = CSSLength.resolveLength(values[1]!, renderStyle, propertyName);
      } else {
        value = CSSLength.resolveLength(propertyValue, renderStyle, propertyName);
      }
      break;
    case PADDING_BOTTOM:
    case MARGIN_BOTTOM:
      List<String?>? values = CSSStyleProperty.getEdgeValues(propertyValue);
      if (values != null && values[2] != null) {
        value = CSSLength.resolveLength(values[2]!, renderStyle, propertyName);
      } else {
        value = CSSLength.resolveLength(propertyValue, renderStyle, propertyName);
      }
      break;
    case PADDING_LEFT:
    case MARGIN_LEFT:
      List<String?>? values = CSSStyleProperty.getEdgeValues(propertyValue);
      if (values != null && values[3] != null) {
        value = CSSLength.resolveLength(values[3]!, renderStyle, propertyName);
      } else {
        value = CSSLength.resolveLength(propertyValue, renderStyle, propertyName);
      }
      break;
    case FLEX_DIRECTION:
      value = CSSFlexboxMixin.resolveFlexDirection(propertyValue);
      break;
    case FLEX_WRAP:
      value = CSSFlexboxMixin.resolveFlexWrap(propertyValue);
      break;
    case ALIGN_CONTENT:
      value = CSSFlexboxMixin.resolveAlignContent(propertyValue);
      break;
    case ALIGN_ITEMS:
      value = CSSFlexboxMixin.resolveAlignItems(propertyValue);
      break;
    case JUSTIFY_CONTENT:
      value = CSSFlexboxMixin.resolveJustifyContent(propertyValue);
      break;
    case JUSTIFY_ITEMS:
      value = CSSGridParser.parseAxisAlignment(propertyValue, allowAuto: false);
      break;
    case JUSTIFY_SELF:
      value = CSSGridParser.parseAxisAlignment(propertyValue, allowAuto: true);
      break;
    case ALIGN_SELF:
      value = CSSFlexboxMixin.resolveAlignSelf(propertyValue);
      break;
    case FLEX_GROW:
      value = CSSFlexboxMixin.resolveFlexGrow(propertyValue);
      break;
    case FLEX_SHRINK:
      value = CSSFlexboxMixin.resolveFlexShrink(propertyValue);
      break;
    case ORDER:
      value = CSSOrderMixin.resolveOrder(propertyValue);
      break;
    case SLIVER_DIRECTION:
      value = CSSSliverMixin.resolveAxis(propertyValue);
      break;
    case TEXT_ALIGN:
      value = CSSTextMixin.resolveTextAlign(propertyValue);
      break;
    case TEXT_INDENT:
      value = CSSLength.resolveLength(propertyValue, renderStyle, TEXT_INDENT);
      break;
    case DIRECTION:
      value = CSSTextMixin.resolveDirection(propertyValue);
      break;
    case WRITING_MODE:
      value = CSSWritingModeMixin.resolveWritingMode(propertyValue);
      break;
    case BACKGROUND_ATTACHMENT:
      value = CSSBackground.resolveBackgroundAttachment(propertyValue);
      break;
    case BACKGROUND_IMAGE:
      value = CSSBackground.resolveBackgroundImage(
          propertyValue, renderStyle, propertyName, renderStyle.target.ownerDocument.controller, baseHref);
      break;
    case BACKGROUND_REPEAT:
      value = CSSBackground.resolveBackgroundRepeat(propertyValue);
      break;
    case BACKGROUND_POSITION_X:
      value = CSSPosition.resolveBackgroundPosition(propertyValue, renderStyle, propertyName, true);
      break;
    case BACKGROUND_POSITION_Y:
      value = CSSPosition.resolveBackgroundPosition(propertyValue, renderStyle, propertyName, false);
      break;
    case BACKGROUND_SIZE:
      value = CSSBackground.resolveBackgroundSize(propertyValue, renderStyle, propertyName);
      break;
    case BACKGROUND_CLIP:
      value = CSSBackground.resolveBackgroundClip(propertyValue);
      break;
    case BACKGROUND_ORIGIN:
      value = CSSBackground.resolveBackgroundOrigin(propertyValue);
      break;
    case BORDER_LEFT_WIDTH:
    case BORDER_TOP_WIDTH:
    case BORDER_RIGHT_WIDTH:
    case BORDER_BOTTOM_WIDTH:
      // If the value looks like a full border shorthand expanded via var()
      // (e.g., "2px solid red"), extract the width token and parse it.
      if (propertyValue.contains(' ')) {
        final triple = CSSStyleProperty.parseBorderTriple(propertyValue);
        final widthToken = triple != null ? triple[0] : null;
        value = widthToken != null
            ? CSSBorderSide.resolveBorderWidth(widthToken, renderStyle, propertyName)
            : CSSBorderSide.resolveBorderWidth(propertyValue, renderStyle, propertyName);
      } else {
        value = CSSBorderSide.resolveBorderWidth(propertyValue, renderStyle, propertyName);
      }
      break;
    case BORDER_LEFT_STYLE:
    case BORDER_TOP_STYLE:
    case BORDER_RIGHT_STYLE:
    case BORDER_BOTTOM_STYLE:
      if (propertyValue.contains(' ')) {
        final triple = CSSStyleProperty.parseBorderTriple(propertyValue);
        final styleToken = triple != null ? triple[1] : null;
        value = CSSBorderSide.resolveBorderStyle(styleToken ?? propertyValue);
      } else {
        value = CSSBorderSide.resolveBorderStyle(propertyValue);
      }
      break;
    case COLOR:
    case CARETCOLOR:
    case BACKGROUND_COLOR:
    case TEXT_DECORATION_COLOR:
    case BORDER_LEFT_COLOR:
    case BORDER_TOP_COLOR:
    case BORDER_RIGHT_COLOR:
    case BORDER_BOTTOM_COLOR:
      if (propertyValue.contains(' ')) {
        final triple = CSSStyleProperty.parseBorderTriple(propertyValue);
        final colorToken = triple != null ? triple[2] : null;
        value = CSSColor.resolveColor(colorToken ?? propertyValue, renderStyle, propertyName);
      } else {
        value = CSSColor.resolveColor(propertyValue, renderStyle, propertyName);
      }
      break;
    case STROKE:
    case FILL:
      value = CSSPaint.parsePaint(propertyValue, renderStyle: renderStyle);
      break;
    case BOX_SHADOW:
      value = CSSBoxShadow.parseBoxShadow(propertyValue, renderStyle, propertyName);
      break;
    case BORDER_TOP_LEFT_RADIUS:
    case BORDER_TOP_RIGHT_RADIUS:
    case BORDER_BOTTOM_LEFT_RADIUS:
    case BORDER_BOTTOM_RIGHT_RADIUS:
      value = CSSBorderRadius.parseBorderRadius(propertyValue, renderStyle, propertyName);
      break;
    case OPACITY:
      value = CSSOpacityMixin.resolveOpacity(propertyValue);
      break;
    case VISIBILITY:
      value = CSSVisibilityMixin.resolveVisibility(propertyValue);
      break;
    case CONTENT_VISIBILITY:
      value = CSSContentVisibilityMixin.resolveContentVisibility(propertyValue);
      break;
    case TRANSFORM:
      value = CSSTransformMixin.resolveTransform(propertyValue);
      break;
    case FILTER:
      value = CSSFunction.parseFunction(propertyValue);
      break;
    case TRANSFORM_ORIGIN:
      value = CSSOrigin.parseOrigin(propertyValue, renderStyle, propertyName);
      break;
    case OBJECT_FIT:
      value = CSSObjectFitMixin.resolveBoxFit(propertyValue);
      break;
    case OBJECT_POSITION:
      value = CSSObjectPositionMixin.resolveObjectPosition(propertyValue);
      break;
    case TEXT_DECORATION_LINE:
      value = CSSText.resolveTextDecorationLine(propertyValue);
      break;
    case TEXT_DECORATION_STYLE:
      value = CSSText.resolveTextDecorationStyle(propertyValue);
      break;
    case FONT_WEIGHT:
      value = CSSText.resolveFontWeight(propertyValue);
      break;
    case FONT_SIZE:
      value = CSSText.resolveFontSize(propertyValue, renderStyle, propertyName);
      break;
    case FONT_STYLE:
      value = CSSText.resolveFontStyle(propertyValue);
      break;
    case FONT_FAMILY:
      value = CSSText.resolveFontFamilyFallback(propertyValue);
      break;
    case LINE_HEIGHT:
      value = CSSText.resolveLineHeight(propertyValue, renderStyle, propertyName);
      break;
    case LETTER_SPACING:
      value = CSSText.resolveSpacing(propertyValue, renderStyle, propertyName);
      break;
    case WORD_SPACING:
      value = CSSText.resolveSpacing(propertyValue, renderStyle, propertyName);
      break;
    case TEXT_SHADOW:
      value = CSSText.resolveTextShadow(propertyValue, renderStyle, propertyName);
      break;
    case WHITE_SPACE:
      value = CSSText.resolveWhiteSpace(propertyValue);
      break;
    case TEXT_OVERFLOW:
      // Overflow will affect text-overflow ellipsis taking effect
      value = CSSText.resolveTextOverflow(propertyValue);
      break;
    case WORD_BREAK:
      value = CSSText.resolveWordBreak(propertyValue);
      break;
    case GRID_TEMPLATE_COLUMNS:
      value = CSSGridParser.parseTrackList(propertyValue, this, propertyName, Axis.horizontal);
      break;
    case GRID_TEMPLATE_ROWS:
      value = CSSGridParser.parseTrackList(propertyValue, this, propertyName, Axis.vertical);
      break;
    case GRID_TEMPLATE_AREAS:
      value = CSSGridParser.parseTemplateAreas(propertyValue);
      break;
    case GRID_AUTO_ROWS:
      value = CSSGridParser.parseTrackList(propertyValue, this, propertyName, Axis.vertical);
      break;
    case GRID_AUTO_COLUMNS:
      value = CSSGridParser.parseTrackList(propertyValue, this, propertyName, Axis.horizontal);
      break;
    case GRID_AUTO_FLOW:
      value = CSSGridParser.parseAutoFlow(propertyValue);
      break;
    case GRID_ROW_START:
    case GRID_ROW_END:
    case GRID_COLUMN_START:
    case GRID_COLUMN_END:
      value = CSSGridParser.parsePlacement(propertyValue);
      break;
    case GRID_AREA_INTERNAL:
      value = propertyValue == 'auto' ? null : propertyValue;
      break;
    case TEXT_TRANSFORM:
      value = CSSText.resolveTextTransform(propertyValue);
      break;
    case LINE_CLAMP:
      value = CSSText.parseLineClamp(propertyValue);
      break;
    case TAB_SIZE:
      // CSS tab-size accepts <number> (and <length> in spec, but we currently treat it as number of spaces)
      value = CSSNumber.parseNumber(propertyValue);
      break;
    case VERTICAL_ALIGN:
      value = CSSInlineMixin.resolveVerticalAlign(propertyValue);
      break;
    // Transition
    case TRANSITION_DELAY:
    case TRANSITION_DURATION:
    case TRANSITION_TIMING_FUNCTION:
    case TRANSITION_PROPERTY:
      value = CSSStyleProperty.getMultipleValues(propertyValue);
      break;
    // Animation
    case ANIMATION_DELAY:
    case ANIMATION_DIRECTION:
    case ANIMATION_DURATION:
    case ANIMATION_FILL_MODE:
    case ANIMATION_ITERATION_COUNT:
    case ANIMATION_NAME:
    case ANIMATION_PLAY_STATE:
    case ANIMATION_TIMING_FUNCTION:
      value = CSSStyleProperty.getMultipleValues(propertyValue);
      break;
    case D:
      value = CSSPath.parseValue(propertyValue);
      break;
  }

  return value;
}