handleResolveValues method

void handleResolveValues(
  1. int? id,
  2. Map<String, dynamic> params
)

Resolves a list of CSS property values in the context of a node's render style. Params:

  • nodeId: frontend node id
  • declarations: { name: 'width', value: '50%' }, ... OR
  • text: 'width:50%; height: 10px;' Returns: { resolved: { name: 'width', value: '160px' }, ... }

Implementation

void handleResolveValues(int? id, Map<String, dynamic> params) {
  final ctx = dbgContext;
  if (ctx == null) {
    sendToFrontend(id, JSONEncodableMap({'results': [], 'resolved': []}));
    return;
  }

  final int? frontendNodeId = params['nodeId'] as int?;
  if (frontendNodeId == null) {
    sendToFrontend(id, JSONEncodableMap({'results': [], 'resolved': []}));
    return;
  }

  final targetId = ctx.getTargetIdByNodeId(frontendNodeId);
  final BindingObject? obj = targetId != null && targetId != 0
      ? ctx.getBindingObject(Pointer.fromAddress(targetId))
      : null;
  final Element? element = obj is Element ? obj : null;
  if (element == null) {
    sendToFrontend(id, JSONEncodableMap({'results': [], 'resolved': []}));
    return;
  }

  // Spec path: values + optional propertyName
  if (params['values'] is List) {
    final List<dynamic> values = params['values'] as List<dynamic>;
    final String? propNameRaw = params['propertyName'] as String?;
    final String? propName =
        (propNameRaw != null && propNameRaw.isNotEmpty) ? camelize(propNameRaw) : null;
    final results = <String>[];
    for (final v0 in values) {
      final input = v0?.toString() ?? '';
      String out = input;
      try {
        dynamic resolved;
        if (propName != null) {
          resolved = element.renderStyle
              .resolveValue(propName, input, baseHref: element.ownerDocument.controller.url);
        } else {
          // Combined syntax fallback not fully supported; leave as-is.
          resolved = null;
        }
        if (resolved is CSSLengthValue) {
          out = resolved.cssText();
        } else if (resolved != null) {
          out = resolved.toString();
        }
      } catch (_) {}
      results.add(out);
    }
    sendToFrontend(id, JSONEncodableMap({'results': results}));
    return;
  }

  // Backward-compat path: declarations/text (non-standard)
  List<Map<String, String>> pairs = [];
  final decls = params['declarations'];
  if (decls is List) {
    for (final d in decls) {
      if (d is Map && d['name'] is String && d['value'] is String) {
        pairs.add({'name': d['name'] as String, 'value': d['value'] as String});
      }
    }
  } else {
    final text = params['text'];
    if (text is String && text.trim().isNotEmpty) {
      final parts = _splitDeclarations(text);
      for (final decl in parts) {
        final int colon = decl.indexOf(':');
        if (colon <= 0) continue;
        final name = decl.substring(0, colon).trim();
        final value = decl.substring(colon + 1).trim();
        if (name.isEmpty) continue;
        pairs.add({'name': name, 'value': value});
      }
    }
  }

  List<Map<String, String>> resolved = [];
  for (final p in pairs) {
    final origName = p['name']!;
    final camel = camelize(origName);
    final value = p['value']!;
    try {
      final v = element.renderStyle.resolveValue(camel, value, baseHref: element.ownerDocument.controller.url);
      String text;
      if (v is CSSLengthValue) {
        text = v.cssText();
      } else {
        text = v?.toString() ?? value;
      }
      resolved.add({'name': origName, 'value': text});
    } catch (_) {
      resolved.add({'name': origName, 'value': value});
    }
  }

  if (DebugFlags.enableDevToolsProtocolLogs) {
    try {
      devToolsProtocolLogger.finer('[DevTools] CSS.resolveValues node=$frontendNodeId count=${resolved.length}');
    } catch (_) {}
  }
  sendToFrontend(id, JSONEncodableMap({'results': resolved.map((e) => e['value']).toList(), 'resolved': resolved}));
}