Skip to content

Conversation

@CGQAQ
Copy link
Contributor

@CGQAQ CGQAQ commented Jan 9, 2026

  • fix(css): align !important semantics across cascade
  • perf(css): speed up CSSStyleDeclaration union/merge
  • perf(css): skip pseudo-element matching when unused
  • refactor(css): make inline styles Dart-only
  • perf(css): gate pseudo emissions by rule features
  • test(css): update snapshot for relayout-align-to-stretch integration test
  • fix(bridge): stabilize style export traversal
  • perf(bridge): treat kLocalStyleChange as element-only

Summary by CodeRabbit

  • New Features

    • Inline and sheet styles now support !important and explicit sheet-style updates for correct cascade behavior.
    • Better support for pseudo-element styles (before/after/first-letter/first-line).
  • Bug Fixes

    • More accurate style merging and fallback between inline and stylesheet rules; computed styles reflect priority changes.
  • Chores

    • Refactored style handling and improved style recalculation performance (reduced traversal work, caching).
  • Tests

    • Added and updated unit/integration tests covering important semantics and inline/sheet interactions.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
use-case Ready Ready Preview, Comment Jan 9, 2026 1:45pm
vue_usecase Ready Ready Preview, Comment Jan 9, 2026 1:45pm

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Consolidates inline-style handling to legacy declarations, adds !important tracking and propagation across native and Dart layers, splits sheet vs inline UI commands, and refactors style cascade/engine to stage and emit sheet/inline/pseudo styles via the bridge.

Changes

Cohort / File(s) Summary
Element style API & conversion
bridge/bindings/qjs/converter_impl.h, bridge/core/dom/element.h, bridge/core/dom/element.cc, bridge/core/dom/element.d.ts, bridge/core/dom/legacy/element_attributes.cc
Removed ElementStyle variant and related Converter specialization; Element::style() now returns legacy inline declaration pointer; visitor-based paths removed and direct access used.
Legacy inline style: !important support
bridge/core/css/legacy/legacy_inline_css_style_declaration.h, .../legacy_inline_css_style_declaration.cc, .../legacy_inline_css_style_declaration_test.cc
Track important properties, propagate priority in InternalSetProperty, parse/emit !important in cssText, and include important flag in UI payloads; tests added/updated.
Style engine & resolver refactor
bridge/core/css/style_engine.cc, bridge/core/css/style_engine.h, bridge/core/css/resolver/style_cascade.cc, bridge/core/css/resolver/*, bridge/core/css/rule_feature_set.*, bridge/core/css/resolver/style_resolver.*
Iterative subtree traversal, two-phase rule collection/cascade export, per-element feature gating for pseudo-elements, removed native inline-style matching (forwarded/merged via bridge), added pseudo-feature flags.
UI command & bridge protocol changes
bridge/foundation/ui_command_buffer.h, .../ui_command_buffer.cc, bridge/foundation/shared_ui_command.h, .../shared_ui_command.cc, bridge/foundation/native_type.h, webf/lib/src/bridge/to_native.dart, webf/lib/src/bridge/ui_command.dart, webf/lib/src/bridge/native_types.dart
Rename kSetStyle → kSetInlineStyle; add kClearSheetStyle, kSetSheetStyle, kSetSheetStyleById and corresponding fast-path APIs; add important field to native payload; encode importance in by-id path; bridge parses and forwards importance.
DOM & Dart CSS model changes
webf/lib/src/css/style_declaration.dart, webf/lib/src/css/computed_style_declaration.dart, webf/lib/src/css/parser/parser.dart, webf/lib/src/css/element_rule_collector.dart, webf/lib/src/css/rule_set.dart, webf/lib/src/css/animation.dart
Introduced CSSPropertyValue/PropertyType (inline/sheet), staged pending vs committed properties, ElementCSSStyleDeclaration with pseudo-element support, parseInlineStyle → InlineStyleEntry, enqueueInline/SheetProperty APIs.
Dart Element & view integration
webf/lib/src/dom/element.dart, webf/lib/src/html/*, webf/lib/src/widget/widget_element.dart, webf/lib/src/launcher/view_controller.dart, webf/lib/src/devtools/cdp_service/modules/css.dart
Element.style → ElementCSSStyleDeclaration, inlineStyle map now InlineStyleEntry (value+important), added _sheetStyle, setSheetStyle/clearSheetStyle, extended setInlineStyle signatures to accept important, preserved important across clone/FFI.
Tests & infra
many tests and test infra: bridge/core/css/blink_inline_style_validation_test.cc, .../inline_css_style_declaration_test.cc, bridge/foundation/*_test.cc, webf/test/src/css/*, integration_tests/specs/css/css-inline/important-semantics.ts, bridge/test/css_unittests.cmake
Updated tests to kSetInlineStyle and new payloads; added many new unit/integration tests for important semantics, merge/union, and native-driven inline important behavior; test runner additions and minor test fixes.
Misc & formatting
bridge/core/css/resolver/cascade_map.*, bridge/core/frame/window.cc, webf/example/lib/main.dart, webf/test/local_http_server.dart
Minor comment/formating changes; example enables Blink by default in example; LocalHttpServer retries on port conflicts.

Sequence Diagram(s)

sequenceDiagram
  participant JS as JS/Client
  participant Bridge as Native Bridge
  participant StyleEngine as Native StyleEngine
  participant UI as UICommandBuffer/SharedUICommand
  participant Dart as Dart/View

  JS->>Bridge: setInlineStyle(elementId, property, value, important?)
  Bridge->>StyleEngine: enqueue inline/sheet update or forward to Dart
  StyleEngine-->>UI: Add (kSetInlineStyle | kSetSheetStyle) with value/href/important
  UI->>Dart: deliver command (setInlineStyle/setSheetStyle / setSheetStyleById)
  Dart->>Dart: view.applyStyle(elementId, property, value, important)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • andycall

Poem

🐰 I nibble bugs and hop through trees,
I stash !important like crunchy peas,
Inline and sheet, now each has a name,
Pseudo petals bloom in the style game,
Queued and flushed — hooray, CSS with ease! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.12% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: css important semantics' is directly related to the main objective of the PR: aligning !important semantics across the CSS cascade.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (10)
webf/test/src/css/inset_shorthand_test.dart (1)

56-65: Inconsistent type usage needs clarification or standardization.

The "removes to initial longhands" test uses ElementCSSStyleDeclaration while all other tests in this file use CSSStyleDeclaration. Based on the commit context ("treat kLocalStyleChange as element-only"), this type change appears intentional. However, since both types are functionally equivalent for this test (both use PropertyType.inline by default and share the same removeProperty implementation), the inconsistency lacks explanation.

Either add a comment explaining why this specific test requires ElementCSSStyleDeclaration, or standardize all tests to use the same type for consistency and clarity.

bridge/core/css/resolver/style_resolver.cc (1)

287-308: Verify no native-side style consumers still rely on inline styles being applied here.

With inline declarations removed from MatchAllRules() (Line 306-308), any native computation that expects ComputedStyle to already reflect style="" / CSSOM changes will be wrong unless the Dart-side merge is guaranteed to run before those code paths (and with correct !important/origin precedence).

Please double-check:

  • native layout/paint/style-recalc paths only consume styles after Dart merge, and
  • precedence is correct across origins (UA/user/author/inline) for both normal and !important declarations.
webf/example/lib/main.dart (1)

49-57: Add enableBlink: true to the fallback controller creation for consistency.

The preloaded controller (line 49-57) explicitly sets enableBlink: true, but the fallback controller created in the createController callback (line 377-411) does not. While the preloaded controller will typically be reused, if it's ever disposed and needs to be recreated (due to maxAliveInstances limits), the new instance would lack this setting, causing inconsistent behavior.

Add enableBlink to the fallback controller
 createController: () =>
     WebFController(
+      enableBlink: true,
       routeObserver: routeObserver,
       initialRoute: widget.initialRoute,
       onControllerInit: (controller) async {},
webf/lib/src/widget/widget_element.dart (1)

118-128: Check rebuild gating logic when important priority changes—the fix requires a different API approach.

shouldElementRebuild() currently compares only values, missing priority changes. If a property value stays the same but important flips, the cascade can change without triggering a widget rebuild. However, the codebase does not expose style.getPropertyPriority(); instead, access the inline style entry directly before calling super.setInlineStyle():

Corrected fix
 void setInlineStyle(String property, String value,
       {String? baseHref, bool fromNative = false, bool important = false}) {
-    bool shouldRebuild = shouldElementRebuild(property, style.getPropertyValue(property), value);
+    final previousEntry = inlineStyle[property];
+    final previousPriority = previousEntry?.important ?? false;
+    final shouldRebuild =
+        shouldElementRebuild(property, style.getPropertyValue(property), value) ||
+        previousPriority != important;
     super.setInlineStyle(property, value,
         baseHref: baseHref, fromNative: fromNative, important: important);
     if (state != null && shouldRebuild) {
       state!.requestUpdateState();
     }
     styleDidUpdate(property, value);
   }
webf/lib/src/css/computed_style_declaration.dart (1)

102-111: Add missing @override annotation to setProperty method.

The parent class CSSStyleDeclaration.setProperty has an identical signature with the PropertyType? propertyType parameter. Since ComputedStyleDeclaration.setProperty overrides this method, the @override annotation must be present to comply with Dart code style guidelines.

  @override
  void setProperty(
    String propertyName,
    String? value, {
    bool? isImportant,
    PropertyType? propertyType,
    String? baseHref,
    bool validate = true,
  }) {
    throw UnimplementedError('No Modification Allowed');
  }
webf/lib/src/bridge/ui_command.dart (2)

137-265: Dart switch has duplicate case labels (won’t compile).
In the command-log switch(command.type), setPseudoStyle, removePseudoStyle, and clearPseudoStyle appear twice (Line 217-254 and again Line 245-254). This is a hard compile-time error in Dart.

Proposed fix (remove duplicate cases and keep the richer payload logger)
         case UICommandType.setPseudoStyle:
           if (command.nativePtr2 != nullptr) {
             try {
               final Pointer<NativePseudoStyleWithHref> payload =
                   command.nativePtr2.cast<NativePseudoStyleWithHref>();
@@
           break;
-        case UICommandType.removePseudoStyle:
-          printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} remove: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-          break;
-        case UICommandType.clearPseudoStyle:
-          printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args}';
-          break;
-        case UICommandType.setPseudoStyle:
-          printMsg =
-              'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} cssText: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-          break;
-        case UICommandType.removePseudoStyle:
-          printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} remove: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-          break;
-        case UICommandType.clearPseudoStyle:
-          printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args}';
-          break;
         case UICommandType.setAttribute:
           printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} key: ${nativeStringToString(command.nativePtr2.cast<NativeString>())} value: ${command.args}';
           break;

284-292: FFI leak: toNativeUtf8() result is never freed on RAF error path.

('Error: $e\n$stack').toNativeUtf8() allocates native memory that is passed to rafCallback() but never freed. Wrap the callback invocation in a try-finally block to ensure cleanup with malloc.free().

Proposed fix
             } catch (e, stack) {
               Pointer<Utf8> nativeErrorMessage = ('Error: $e\n$stack').toNativeUtf8();
-              rafCallback(command.nativePtr.cast<Void>(), view.contextId, highResTimeStamp, nativeErrorMessage);
+              try {
+                rafCallback(command.nativePtr.cast<Void>(), view.contextId, highResTimeStamp, nativeErrorMessage);
+              } finally {
+                malloc.free(nativeErrorMessage);
+              }
             }
bridge/core/css/legacy/legacy_inline_css_style_declaration.cc (1)

66-87: Fix potential UB: ctype calls must use unsigned char.
std::isupper(c) / std::tolower(c) (Line 77-80) are undefined for negative char values.

Proposed fix
   for (char c : propertyName) {
-    if (std::isupper(c)) {
+    const unsigned char uc = static_cast<unsigned char>(c);
+    if (std::isupper(uc)) {
       result += '-';
-      result += std::tolower(c);
+      result += static_cast<char>(std::tolower(uc));
     } else {
       result += c;
     }
   }
bridge/core/dom/element.cc (1)

438-508: Avoid reintroducing element_data_->InlineStyle() snapshots in Blink mode during clone.
CloneNonAttributePropertiesFrom clones legacy inline style (good), but then also clones other.element_data_->InlineStyle() into unique_data->inline_style_ unconditionally (Line 501-507). In Blink mode, you’re explicitly clearing inline_style_ elsewhere to keep inline style “legacy-only”; cloning can undermine that.

Proposed fix (gate snapshot clone to non-Blink mode)
   // Also clone the inline style from element_data_ if it exists
-  if (other.element_data_ && other.element_data_->InlineStyle()) {
+  if (!GetExecutingContext()->isBlinkEnabled() &&
+      other.element_data_ && other.element_data_->InlineStyle()) {
     if (element_data_ && element_data_->IsUnique()) {
       auto* unique_data = static_cast<UniqueElementData*>(element_data_.get());
       unique_data->inline_style_ = other.element_data_->InlineStyle()->MutableCopy();
     }
   }
webf/lib/src/css/style_declaration.dart (1)

1310-1390: Pseudo rule recomputation can keep stale properties (missing reset before union()).
handlePseudoRules() reuses existing pseudo*Style and only unions new rules, so properties that disappear from matched rules won’t be removed unless the entire pseudo rule set becomes empty. This can leave incorrect pseudo computed styles.

Proposed fix (rebuild pseudo declarations each time)
     if (beforeRules.isNotEmpty) {
-      pseudoBeforeStyle ??= CSSStyleDeclaration.sheet();
-      // Merge all the rules
-      for (CSSStyleRule rule in beforeRules) {
-        pseudoBeforeStyle!.union(rule.declaration);
-      }
+      final CSSStyleDeclaration next = CSSStyleDeclaration.sheet();
+      for (CSSStyleRule rule in beforeRules) {
+        next.union(rule.declaration);
+      }
+      pseudoBeforeStyle = next;
       parentElement.markBeforePseudoElementNeedsUpdate();
     } else if (beforeRules.isEmpty && pseudoBeforeStyle != null) {
       pseudoBeforeStyle = null;
     }
@@
     if (afterRules.isNotEmpty) {
-      pseudoAfterStyle ??= CSSStyleDeclaration.sheet();
-      for (CSSStyleRule rule in afterRules) {
-        pseudoAfterStyle!.union(rule.declaration);
-      }
+      final CSSStyleDeclaration next = CSSStyleDeclaration.sheet();
+      for (CSSStyleRule rule in afterRules) {
+        next.union(rule.declaration);
+      }
+      pseudoAfterStyle = next;
       parentElement.markAfterPseudoElementNeedsUpdate();
     } else if (afterRules.isEmpty && pseudoAfterStyle != null) {
       pseudoAfterStyle = null;
     }
@@
     if (firstLetterRules.isNotEmpty) {
-      pseudoFirstLetterStyle ??= CSSStyleDeclaration.sheet();
-      for (CSSStyleRule rule in firstLetterRules) {
-        pseudoFirstLetterStyle!.union(rule.declaration);
-      }
+      final CSSStyleDeclaration next = CSSStyleDeclaration.sheet();
+      for (CSSStyleRule rule in firstLetterRules) {
+        next.union(rule.declaration);
+      }
+      pseudoFirstLetterStyle = next;
       parentElement.markFirstLetterPseudoNeedsUpdate();
     } else if (firstLetterRules.isEmpty && pseudoFirstLetterStyle != null) {
       pseudoFirstLetterStyle = null;
     }
@@
     if (firstLineRules.isNotEmpty) {
-      pseudoFirstLineStyle ??= CSSStyleDeclaration.sheet();
-      for (CSSStyleRule rule in firstLineRules) {
-        pseudoFirstLineStyle!.union(rule.declaration);
-      }
+      final CSSStyleDeclaration next = CSSStyleDeclaration.sheet();
+      for (CSSStyleRule rule in firstLineRules) {
+        next.union(rule.declaration);
+      }
+      pseudoFirstLineStyle = next;
       parentElement.markFirstLinePseudoNeedsUpdate();
     } else if (firstLineRules.isEmpty && pseudoFirstLineStyle != null) {
       pseudoFirstLineStyle = null;
     }
🤖 Fix all issues with AI agents
In @bridge/core/api/element.cc:
- Around line 17-28: Check ptr for null before using it and check
element->GetExecutingContext() before constructing MemberMutationScope: if ptr
is null return WebFValue<LegacyCssStyleDeclaration,
LegacyCssStyleDeclarationPublicMethods>::Null(); then static_cast to
webf::Element*, call element->GetExecutingContext() into a local (e.g., context)
and if context is null also return Null(); only then construct
MemberMutationScope{context} and proceed as before (retrieve style_declaration,
check it, call KeepAlive(), and return the WebFValue).

In @webf/lib/src/css/css_animation.dart:
- Around line 98-100: The cleanup in _revertOriginProperty() currently skips
removing inline styles when no origin was cached, leaving animation-introduced
properties behind; update _revertOriginProperty() to call
target.setInlineStyle(property, '') whenever origin == null (instead of doing
nothing) so properties applied by beforeRunningAnimation() are removed when the
animation ends or is cancelled; ensure this logic uses the
_cacheOriginProperties lookup and covers both normal revert and cancel paths so
animations with fill: backwards/both don't leave stale inline styles.

In @webf/lib/src/css/style_declaration.dart:
- Around line 770-779: operator== currently compares only hashCode which is
unsafe; change CSSStyleDeclaration.operator== to perform structural equality by
first checking identical(this, other) or runtimeType equality and then comparing
the actual significant fields (at minimum cssText) for equality (e.g., other is
CSSStyleDeclaration and other.cssText == cssText); keep hashCode derived from
the same fields so it remains consistent with equality.
🧹 Nitpick comments (17)
webf/test/src/rendering/css_sizing_test.dart (3)

59-63: Make enqueueInlineProperty() application explicit (flush) for future un-skipping

If enqueueInlineProperty() only queues changes, this test may start failing once skip: true is removed unless you flush before pumping (like you do later in the file).

Proposed change
       // Change width dynamically
       div.style.enqueueInlineProperty('width', '200px');
+      div.style.flushPendingProperties();
       await tester.pump();

236-240: Same: flush queued inline updates before pumping

Keeps test semantics consistent with the later “dynamic style updates” test.

Proposed change
       // Change height dynamically
       div.style.enqueueInlineProperty('height', '250px');
+      div.style.flushPendingProperties();
       await tester.pump();

776-786: Reduce repeated pump() calls to a small loop (same behavior, less noise)

Proposed change
       box.style.flushPendingProperties();
-      await tester.pump();
-      await tester.pump();
-      await tester.pump();
-      await tester.pump();
-      await tester.pump();
-      await tester.pump();
+      for (var i = 0; i < 6; i++) {
+        await tester.pump();
+      }
webf/test/local_http_server.dart (2)

44-49: Consider adding Windows error code for completeness.

The helper correctly detects EADDRINUSE on macOS (48) and Linux (98). The message fallback should handle Windows, but explicitly checking error code 10048 (Windows WSAEADDRINUSE) would improve reliability.

🔧 Optional enhancement for Windows compatibility
 static bool _isAddressInUse(SocketException error) {
   final int? code = error.osError?.errorCode;
-  if (code == 48 || code == 98) return true; // macOS/Linux EADDRINUSE
+  if (code == 48 || code == 98 || code == 10048) return true; // macOS/Linux/Windows EADDRINUSE
   final String message = error.message.toLowerCase();
   return message.contains('address already in use');
 }

51-119: LGTM: Retry mechanism is well-implemented.

The retry logic correctly:

  • Detects address-in-use errors via _isAddressInUse
  • Retries up to 20 times with a new random port
  • Delegates exhausted retries to Zone.current.handleUncaughtError (appropriate for test code)
  • Exits early on line 116 after scheduling retry

One optional improvement: consider logging retry attempts to aid debugging when port conflicts occur frequently in test environments.

📝 Optional: Add logging for retry attempts
 }).catchError((Object error, StackTrace stackTrace) {
   if (error is SocketException && _isAddressInUse(error) && attempt < 20) {
+    print('Port $port in use, retrying with new port (attempt ${attempt + 1}/20)');
     port = _randomPort();
     _startServer(attempt + 1);
     return;
   }
   Zone.current.handleUncaughtError(error, stackTrace);
 });
webf/lib/src/devtools/cdp_service/modules/css.dart (1)

559-582: Batch recalculateStyle() to avoid O(n) full style recalcs during inline-style edits.
Right now _applyInlineStyleText() recalculates after every property set; this is noticeable when DevTools edits multiple declarations.

Proposed change
   for (String decl in decls) {
@@
-      element.setInlineStyle(camelize(name), value, important: important);
-      element.recalculateStyle();
+      element.setInlineStyle(camelize(name), value, important: important);
   }
+  element.recalculateStyle();
webf/lib/src/css/rule_set.dart (1)

38-41: Consider making hasPseudoElementSelectors private with a getter for defensive programming.

The field is currently public and mutable, but empirical verification shows all external access is read-only (in grouping_content.dart:160 and element.dart:2250). All writes occur only within RuleSet itself (in reset() and findBestRuleSetAndAdd()). While no external writes currently exist, using a private backing field with a public getter prevents future accidental mutations that could silently break pseudo-element matching behavior.

Suggested refactor
 class RuleSet {
-  bool hasPseudoElementSelectors = false;
+  bool _hasPseudoElementSelectors = false;
+  bool get hasPseudoElementSelectors => _hasPseudoElementSelectors;
bridge/core/css/rule_feature_set.h (2)

136-140: Consider updating ToString() docs/legend to reflect new pseudo flags.
You added UsesFirstLetterRules/UsesBeforeRules/UsesAfterRules, but the “META flags” comment block still only documents F/W/R/P/..., which can make debugging confusing if ToString() starts surfacing these.


271-275: New FeatureMetadata flags look correct; consider packing if size matters.
If FeatureMetadata is copied frequently, these additional bools may add padding; a bitfield/bitmask could keep it compact (optional).

bridge/core/css/blink_inline_style_validation_test.cc (1)

29-34: Make the value_ptr cast const-correct to match SharedNativeStringToUTF8.
Right now SharedNativeStringToUTF8 takes const webf::SharedNativeString*, but value_ptr is cast as non-const.

Proposed diff
-      auto* value_ptr = reinterpret_cast<webf::SharedNativeString*>(static_cast<uintptr_t>(item.string_01));
+      const auto* value_ptr =
+          reinterpret_cast<const webf::SharedNativeString*>(static_cast<uintptr_t>(item.string_01));
       value_text = SharedNativeStringToUTF8(value_ptr);

Also applies to: 78-84

webf/lib/src/css/parser/parser.dart (1)

96-145: Inline !important parsing/validation looks correct; consider camelize() on reset path for consistent keys.
In the resetProperty branch you set propertyIdent = identifier().name; which can differ from the normal camelize(...) format.

bridge/foundation/shared_ui_command.h (1)

49-56: Default important value would make this API harder to misuse.

Since this is a “fast-path” helper similar to AddStyleByIdCommand, consider defaulting important to false to reduce call-site friction and avoid accidental uninitialized/placeholder values.

Proposed tweak
 void AddSheetStyleByIdCommand(void* native_binding_object,
                              int32_t property_id,
                              int64_t value_slot,
                              SharedNativeString* base_href,
-                             bool important,
+                             bool important = false,
                              bool request_ui_update = true);
bridge/core/dom/legacy/element_attributes.cc (1)

134-142: Style attribute serialization: potential allocation/side-effect via element_->style() in ToString().

element_->style() appears to “ensure”/allocate the legacy inline declaration for styled elements; calling it from ToString() can create state during serialization. If that’s intended (to serialize normalized parsed style), fine—otherwise consider a non-allocating accessor if one exists.

webf/lib/src/html/grouping_content.dart (1)

152-156: Inline styles propagate importance flag correctly.

The use of enqueueInlineProperty with isImportant: entry.important ? true : null properly propagates the per-entry importance flag. However, the ternary entry.important ? true : null could be simplified.

♻️ Optional simplification
-        style.enqueueInlineProperty(propertyName, entry.value, isImportant: entry.important ? true : null);
+        style.enqueueInlineProperty(propertyName, entry.value, isImportant: entry.important);

If isImportant accepts bool? and entry.important is already a bool, you can pass it directly unless the API specifically requires null for false values.

webf/lib/src/bridge/ui_command.dart (1)

121-123: Use a Set<int> for pendingStylePropertiesTargets (it’s a set, not a map).
You only care about unique addresses; Set<int> reduces noise and intent is clearer.

[detail optional]

  • Replace Map<int, bool> with final pendingStylePropertiesTargets = <int>{};
  • Replace assignments with pendingStylePropertiesTargets.add(nativePtr.address);

Also applies to: 356-467, 576-585

webf/lib/src/dom/element.dart (2)

2009-2091: setInlineStyle() correctness looks OK; consider de-duplicating legacy !important decoding.
You now have near-identical !important suffix decoding in setInlineStyle() and setSheetStyle(), plus _normalizeInlineStyleEntryFromNative(). A shared helper would reduce drift risk.


2319-2370: InlineStyleEntry-based removal + native normalization helper look OK; ensure normalization is used consistently.
If _normalizeInlineStyleEntryFromNative() is meant to be the canonical legacy !important detector (quote/paren-safe), consider using it in both inline/sheet paths rather than maintaining two decoders.

Comment on lines 17 to 28
WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods> ElementPublicMethods::Style(Element* ptr) {
auto* element = static_cast<webf::Element*>(ptr);
MemberMutationScope member_mutation_scope{element->GetExecutingContext()};
auto style = element->style();
auto* style_declaration = element->style();
if (!style_declaration) {
return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>::Null();
}

return std::visit(
MakeVisitor(
[&](legacy::LegacyInlineCssStyleDeclaration* styleDeclaration) {
WebFValueStatus* status_block = styleDeclaration->KeepAlive();
return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>(
styleDeclaration, styleDeclaration->legacyCssStyleDeclarationPublicMethods(), status_block);
},
[](auto&&) { return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>::Null(); }),
style);
WebFValueStatus* status_block = style_declaration->KeepAlive();
return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>(
style_declaration, style_declaration->legacyCssStyleDeclarationPublicMethods(), status_block);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the Element class definition and understand GetExecutingContext()
fd -t f -e h -e hpp "element\." bridge/ | head -20

Repository: openwebf/webf

Length of output: 866


🏁 Script executed:

# Search for Element class definition
rg "class Element" bridge/ -t cpp -t h -A 3

Repository: openwebf/webf

Length of output: 27727


🏁 Script executed:

# Find GetExecutingContext() method
rg "GetExecutingContext" bridge/ -t cpp -t h -B 2 -A 3

Repository: openwebf/webf

Length of output: 50370


🏁 Script executed:

# Check MemberMutationScope constructor
rg "MemberMutationScope" bridge/ -t cpp -t h -B 2 -A 5

Repository: openwebf/webf

Length of output: 50369


🏁 Script executed:

# Check KeepAlive() method signature
rg "KeepAlive\(\)" bridge/ -t cpp -t h -B 2 -A 3

Repository: openwebf/webf

Length of output: 17213


🏁 Script executed:

# Find MemberMutationScope class definition and constructor
rg "class MemberMutationScope" bridge/ -t cpp -t h -A 10

Repository: openwebf/webf

Length of output: 1450


🏁 Script executed:

# Check how ptr is used - is it a valid opaque pointer from FFI?
rg "ElementPublicMethods::Style" bridge/ -t cpp -t h -B 3 -A 3

Repository: openwebf/webf

Length of output: 560


🏁 Script executed:

# Look for callers of ElementPublicMethods::Style to see if they guard ptr
rg "Style\(" bridge/core/api/ -t cpp -A 2 -B 2 | head -50

Repository: openwebf/webf

Length of output: 459


🏁 Script executed:

# Find MemberMutationScope constructor implementation
rg "MemberMutationScope::MemberMutationScope" bridge/ -t cpp -A 10

Repository: openwebf/webf

Length of output: 894


🏁 Script executed:

# Check if Element::GetExecutingContext() is defined and look at its return type
rg "GetExecutingContext()" bridge/core/dom/element.h -A 2 -B 2

Repository: openwebf/webf

Length of output: 39


🏁 Script executed:

# Check the actual implementation to see how it can be null in execution
rg -A 5 "MemberMutationScope\(ExecutingContext" bridge/bindings/qjs/cppgc/mutation_scope.cc

Repository: openwebf/webf

Length of output: 283


Add defensive null checks for ptr and GetExecutingContext().

The current code directly dereferences ptr without checking and passes element->GetExecutingContext() to MemberMutationScope without verifying it's non-null. The MemberMutationScope constructor immediately dereferences the context pointer (calling context->GetScriptState() and context->SetMutationScope()), which will crash if null. Since GetExecutingContext() can legitimately return null (as seen in similar code paths), this needs defensive checks. Also note the asymmetry: style_declaration is checked for null (lines 21–23) but GetExecutingContext() is not.

Proposed patch
 WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods> ElementPublicMethods::Style(Element* ptr) {
+  if (!ptr) {
+    return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>::Null();
+  }
   auto* element = static_cast<webf::Element*>(ptr);
-  MemberMutationScope member_mutation_scope{element->GetExecutingContext()};
+  auto* context = element->GetExecutingContext();
+  if (!context) {
+    return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>::Null();
+  }
+  MemberMutationScope member_mutation_scope{context};
   auto* style_declaration = element->style();
   if (!style_declaration) {
     return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>::Null();
   }

   WebFValueStatus* status_block = style_declaration->KeepAlive();
   return WebFValue<LegacyCssStyleDeclaration, LegacyCssStyleDeclarationPublicMethods>(
       style_declaration, style_declaration->legacyCssStyleDeclarationPublicMethods(), status_block);
 }
🤖 Prompt for AI Agents
In @bridge/core/api/element.cc around lines 17 - 28, Check ptr for null before
using it and check element->GetExecutingContext() before constructing
MemberMutationScope: if ptr is null return WebFValue<LegacyCssStyleDeclaration,
LegacyCssStyleDeclarationPublicMethods>::Null(); then static_cast to
webf::Element*, call element->GetExecutingContext() into a local (e.g., context)
and if context is null also return Null(); only then construct
MemberMutationScope{context} and proceed as before (retrieve style_declaration,
check it, call KeepAlive(), and return the WebFValue).

Comment on lines 98 to 100
final Map<String, Animation> _runningAnimation = {};
final Map<String, String> _cacheOriginProperties = {};
final Map<String, InlineStyleEntry> _cacheOriginProperties = {};

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for removal/clear APIs for inline styles
rg -n --hidden -S 'removeInlineStyle\s*\(|clearInlineStyle\s*\(|removeProperty\s*\(' webf/lib/src/dom webf/lib/src/css 2>/dev/null || echo "No exact matches found"

# Search more broadly for removal methods
rg -n 'def.*remove.*[Ss]tyle|def.*clear.*[Ss]tyle' webf/lib/src --type=dart 2>/dev/null || true

Repository: openwebf/webf

Length of output: 17827


🏁 Script executed:

#!/bin/bash
# Find InlineStyleEntry definition
rg -n 'class\s+InlineStyleEntry\b' webf/lib/src

Repository: openwebf/webf

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Also examine the css_animation.dart file to see the implementation at the specified lines
wc -l webf/lib/src/css/css_animation.dart

Repository: openwebf/webf

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Inspect InlineStyleEntry definition and implementation
sed -n '106,150p' webf/lib/src/css/style_declaration.dart

Repository: openwebf/webf

Length of output: 1829


🏁 Script executed:

#!/bin/bash
# Read the css_animation.dart file to see the full context at specified lines
sed -n '95,110p' webf/lib/src/css/css_animation.dart
sed -n '140,155p' webf/lib/src/css/css_animation.dart
sed -n '260,280p' webf/lib/src/css/css_animation.dart

Repository: openwebf/webf

Length of output: 1722


🏁 Script executed:

#!/bin/bash
# Verify if setInlineStyle can be called with null to remove a property
rg -n 'void setInlineStyle' webf/lib/src/dom/element.dart -A 10

Repository: openwebf/webf

Length of output: 732


🏁 Script executed:

#!/bin/bash
# Check the context of line 348 in element.dart to see how _removeInlineStyle works
sed -n '2315,2335p' webf/lib/src/dom/element.dart

Repository: openwebf/webf

Length of output: 629


🏁 Script executed:

#!/bin/bash
# Check if there's a way to remove an inline style property (null case for setInlineStyle)
sed -n '2009,2100p' webf/lib/src/dom/element.dart | head -60

Repository: openwebf/webf

Length of output: 2630


🏁 Script executed:

#!/bin/bash
# Verify the full context of how _revertOriginProperty is called and whether it handles the "no origin" case
sed -n '250,310p' webf/lib/src/css/css_animation.dart

Repository: openwebf/webf

Length of output: 1974


Remove animation-introduced inline styles when no origin property existed.
When beforeRunningAnimation() applies animation values as inline styles and no origin existed, _revertOriginProperty() skips cleanup (since there's nothing cached to restore). Those styles remain as inline declarations after the animation finishes or is cancelled.

Use target.setInlineStyle(property, '') in _revertOriginProperty() when origin == null to properly remove the property, ensuring animations with fill: backwards or fill: both don't leave behind stale inline styles.

Affects lines 142–148 and 264–273.

🤖 Prompt for AI Agents
In @webf/lib/src/css/css_animation.dart around lines 98 - 100, The cleanup in
_revertOriginProperty() currently skips removing inline styles when no origin
was cached, leaving animation-introduced properties behind; update
_revertOriginProperty() to call target.setInlineStyle(property, '') whenever
origin == null (instead of doing nothing) so properties applied by
beforeRunningAnimation() are removed when the animation ends or is cancelled;
ensure this logic uses the _cacheOriginProperties lookup and covers both normal
revert and cancel paths so animations with fill: backwards/both don't leave
stale inline styles.

Comment on lines +139 to 160
/// An empty style declaration.
static CSSStyleDeclaration empty = CSSStyleDeclaration();

final Map<String, CSSPropertyValue> _properties = {};

CSSPropertyValue? _getEffectivePropertyValueEntry(String propertyName) => _properties[propertyName];

void _setStagedPropertyValue(String propertyName, CSSPropertyValue value) {
_properties[propertyName] = value;
}

// ::first-letter pseudo style (applies to the first typographic letter)
CSSStyleDeclaration? _pseudoFirstLetterStyle;
CSSStyleDeclaration? get pseudoFirstLetterStyle => _pseudoFirstLetterStyle;
set pseudoFirstLetterStyle(CSSStyleDeclaration? newStyle) {
_pseudoFirstLetterStyle = newStyle;
// Trigger a layout rebuild so IFC can re-shape text for first-letter styling
target?.markFirstLetterPseudoNeedsUpdate();
List<String> _effectivePropertyNamesSnapshot() => _properties.keys.toList(growable: false);

static bool _samePropertyValue(CSSPropertyValue? a, CSSPropertyValue? b) {
if (identical(a, b)) return true;
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.value == b.value &&
a.baseHref == b.baseHref &&
a.important == b.important &&
a.propertyType == b.propertyType;
}
Copy link

@coderabbitai coderabbitai bot Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

CSSStyleDeclaration.empty should not be mutable shared state.
static CSSStyleDeclaration empty = CSSStyleDeclaration(); is globally shared and can be mutated by accident, polluting “empty” everywhere.

Proposed fix (at least make it non-reassignable + document)
-  static CSSStyleDeclaration empty = CSSStyleDeclaration();
+  /// Shared empty declaration. Treat as read-only; do not mutate.
+  static final CSSStyleDeclaration empty = CSSStyleDeclaration();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// An empty style declaration.
static CSSStyleDeclaration empty = CSSStyleDeclaration();
final Map<String, CSSPropertyValue> _properties = {};
CSSPropertyValue? _getEffectivePropertyValueEntry(String propertyName) => _properties[propertyName];
void _setStagedPropertyValue(String propertyName, CSSPropertyValue value) {
_properties[propertyName] = value;
}
// ::first-letter pseudo style (applies to the first typographic letter)
CSSStyleDeclaration? _pseudoFirstLetterStyle;
CSSStyleDeclaration? get pseudoFirstLetterStyle => _pseudoFirstLetterStyle;
set pseudoFirstLetterStyle(CSSStyleDeclaration? newStyle) {
_pseudoFirstLetterStyle = newStyle;
// Trigger a layout rebuild so IFC can re-shape text for first-letter styling
target?.markFirstLetterPseudoNeedsUpdate();
List<String> _effectivePropertyNamesSnapshot() => _properties.keys.toList(growable: false);
static bool _samePropertyValue(CSSPropertyValue? a, CSSPropertyValue? b) {
if (identical(a, b)) return true;
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.value == b.value &&
a.baseHref == b.baseHref &&
a.important == b.important &&
a.propertyType == b.propertyType;
}
/// Shared empty declaration. Treat as read-only; do not mutate.
static final CSSStyleDeclaration empty = CSSStyleDeclaration();
final Map<String, CSSPropertyValue> _properties = {};
CSSPropertyValue? _getEffectivePropertyValueEntry(String propertyName) => _properties[propertyName];
void _setStagedPropertyValue(String propertyName, CSSPropertyValue value) {
_properties[propertyName] = value;
}
List<String> _effectivePropertyNamesSnapshot() => _properties.keys.toList(growable: false);
static bool _samePropertyValue(CSSPropertyValue? a, CSSPropertyValue? b) {
if (identical(a, b)) return true;
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.value == b.value &&
a.baseHref == b.baseHref &&
a.important == b.important &&
a.propertyType == b.propertyType;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is named constructor

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CGQAQ, I understand the confusion, but this is actually a static field, not a named constructor. Let me clarify:

Named constructors in your class look like this:

CSSStyleDeclaration([super.context]) : _defaultPropertyType = PropertyType.inline;
CSSStyleDeclaration.sheet([super.context]) : _defaultPropertyType = PropertyType.sheet;

The line CodeRabbit is flagging is a static field declaration:

static CSSStyleDeclaration empty = CSSStyleDeclaration();

CodeRabbit's concern is valid:

  1. Without final, this field can be reassigned anywhere in the code:

    CSSStyleDeclaration.empty = someOtherInstance; // Currently allowed
  2. Even with final, the instance itself can still be mutated (properties added/changed), but at least the reference can't be reassigned:

    static final CSSStyleDeclaration empty = CSSStyleDeclaration();
    // Now: CSSStyleDeclaration.empty = x; // ❌ Won't compile
    // But: CSSStyleDeclaration.empty.setProperty(...) // ✅ Still possible

Recommendation: Add final to prevent accidental reassignment. If you want true immutability, you'd need additional patterns (like freezing the instance or using an unmodifiable wrapper), but final is a good first step.


🧠 Learnings used
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/lib/src/css/**/*.dart : Use CSSRenderStyle for style computation and storage in Dart CSS code

Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Follow rules in webf/analysis_options.yaml for Dart code style

Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: CSS property implementations are located in lib/src/css/

Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: No build needed for Dart-only changes in webf/

CGQAQ added 9 commits January 9, 2026 21:17
- Track origin (inline vs sheet) and priority during merges
- Propagate inline style importance through UICommand payloads and legacy parsing
- Add integration/unit tests for important precedence
RuleFeatureSet now tracks usage of ::before/::after/::first-letter alongside
::first-line.

StyleEngine consults the global RuleFeatureSet to avoid emitting/sending pseudo
style payloads for pseudos that cannot match, and stops descending into
display:none subtrees during subtree style recalculation.
StyleEngine::RecalcStyleForSubtree/RecalcStyleForElementOnly now:
- Guard against missing ExecutingContext.
- Cache StyleResolver/UICommandBuffer for the whole operation.
- Switch subtree traversal to an explicit stack and drop unused inherited-state plumbing.
- Detect display:none via CSSValueID when possible (fallback to string compare).
- Reuse pseudo selector atoms and avoid redundant UTF-8 conversions for href payloads.

integration_tests: wait a frame before asserting scrollWidth/clientWidth in translate transform spec.

Tests: not run (not requested)
StyleEngine::RecalcStyle previously handled any dirty element that wasn't\nkInlineIndependentStyleChange by calling RecalcStyleForSubtree(*element).\nThis made self-only invalidations (InvalidatesSelf), style="" mutations,\nand animation marks using kLocalStyleChange trigger expensive subtree rule\nmatching and UI style export.\n\nHandle kLocalStyleChange via RecalcStyleForElementOnly and clear the dirty\nbit. Subtree recalcs are now reserved for kSubtreeStyleChange and the\nexplicit ForceRecalcDescendants path.\n\nThis keeps semantics while avoiding unnecessary DOM subtree traversal.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
webf/example/lib/main.dart (1)

49-61: Keep enableBlink: true consistent across both controller instances.

The pre-registered 'demo' controller (line 51) uses enableBlink: true, but the fallback controller created at line 378 defaults to enableBlink: false. Since both serve the same demoControllerName, ensure the fallback also explicitly sets enableBlink: true to maintain consistency.

Suggested fix
           WebFController(
+            enableBlink: true,
             routeObserver: routeObserver,
             initialRoute: widget.initialRoute,
             onControllerInit: (controller) async {},

Note: enableBlink controls the CSS engine (native Blink vs Dart-side parsing) and is not debug-only, so gating it behind kDebugMode would be inappropriate.

webf/lib/src/bridge/ui_command.dart (2)

217-254: Duplicate case statements for pseudo-style logging.

There are duplicate case handlers in the logging switch statement:

  • setPseudoStyle appears at lines 217 and 245
  • removePseudoStyle appears at lines 239 and 249
  • clearPseudoStyle appears at lines 242 and 252

Only the first matching case will execute. This appears to be dead code from incomplete refactoring.

🔧 Suggested fix: remove duplicate cases
         printMsg =
             'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} property: <null>';
         }
         break;
-      case UICommandType.removePseudoStyle:
-        printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} remove: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-        break;
-      case UICommandType.clearPseudoStyle:
-        printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args}';
-        break;
-      case UICommandType.setPseudoStyle:
-        printMsg =
-            'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} cssText: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-        break;
-      case UICommandType.removePseudoStyle:
-        printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args} remove: ${command.nativePtr2 != nullptr ? nativeStringToString(command.nativePtr2.cast<NativeString>()) : null}';
-        break;
-      case UICommandType.clearPseudoStyle:
-        printMsg = 'nativePtr: ${command.nativePtr} type: ${command.type} pseudo: ${command.args}';
-        break;
       case UICommandType.setAttribute:

441-513: Duplicate execution case statements for pseudo-style.

Similar to the logging switch, there are duplicate case handlers in the execution switch:

  • setPseudoStyle at lines 441 and 468
  • removePseudoStyle at lines 449 and 503
  • clearPseudoStyle at lines 457 and 511

The first setPseudoStyle (lines 441-448) uses nativePairToPairRecord, while the second (lines 468-502) uses NativePseudoStyleWithHref with baseHref support. The second implementation appears more complete. The duplicates should be consolidated.

🔧 Suggested fix: remove older duplicate cases
         pendingStylePropertiesTargets[nativePtr.address] = true;
         break;
-      case UICommandType.setPseudoStyle:
-        if (command.nativePtr2 != nullptr) {
-          final keyValue = nativePairToPairRecord(command.nativePtr2.cast());
-          if (keyValue.key.isNotEmpty) {
-            view.setPseudoStyle(nativePtr, command.args, keyValue.key, keyValue.value);
-          }
-        }
-        break;
-      case UICommandType.removePseudoStyle:
-        if (command.nativePtr2 != nullptr) {
-          Pointer<NativeString> nativeKey = command.nativePtr2.cast<NativeString>();
-          String key = nativeStringToString(nativeKey);
-          freeNativeString(nativeKey);
-          view.removePseudoStyle(nativePtr, command.args, key);
-        }
-        break;
-      case UICommandType.clearPseudoStyle:
-        view.clearPseudoStyle(nativePtr, command.args);
-        break;
       case UICommandType.clearStyle:
🧹 Nitpick comments (5)
webf/lib/src/css/style_declaration.dart (1)

1393-1423: Consider refining pseudo-style update detection in merge().

The merge() method sets pseudoUpdated = true whenever other has a pseudo-style, even when the subsequent merge() call might not produce any actual changes (lines 1404, 1409, 1414, 1419). This could trigger unnecessary pseudo-element updates.

♻️ Optional refinement to track actual changes
   bool merge(CSSStyleDeclaration other) {
     final bool updateStatus = super.merge(other);

     if (other is! ElementCSSStyleDeclaration) return updateStatus;

     bool pseudoUpdated = false;
     // Merge pseudo-element styles. Ensure target side is initialized so rules from
     // 'other' are not dropped when this side is null.
     if (other.pseudoBeforeStyle != null) {
       pseudoBeforeStyle ??= CSSStyleDeclaration.sheet();
-      pseudoBeforeStyle!.merge(other.pseudoBeforeStyle!);
-      pseudoUpdated = true;
+      if (pseudoBeforeStyle!.merge(other.pseudoBeforeStyle!)) {
+        pseudoUpdated = true;
+      }
     }
     if (other.pseudoAfterStyle != null) {
       pseudoAfterStyle ??= CSSStyleDeclaration.sheet();
-      pseudoAfterStyle!.merge(other.pseudoAfterStyle!);
-      pseudoUpdated = true;
+      if (pseudoAfterStyle!.merge(other.pseudoAfterStyle!)) {
+        pseudoUpdated = true;
+      }
     }
     if (other.pseudoFirstLetterStyle != null) {
       pseudoFirstLetterStyle ??= CSSStyleDeclaration.sheet();
-      pseudoFirstLetterStyle!.merge(other.pseudoFirstLetterStyle!);
-      pseudoUpdated = true;
+      if (pseudoFirstLetterStyle!.merge(other.pseudoFirstLetterStyle!)) {
+        pseudoUpdated = true;
+      }
     }
     if (other.pseudoFirstLineStyle != null) {
       pseudoFirstLineStyle ??= CSSStyleDeclaration.sheet();
-      pseudoFirstLineStyle!.merge(other.pseudoFirstLineStyle!);
-      pseudoUpdated = true;
+      if (pseudoFirstLineStyle!.merge(other.pseudoFirstLineStyle!)) {
+        pseudoUpdated = true;
+      }
     }

     return updateStatus || pseudoUpdated;
   }
bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc (1)

14-16: Consider removing or utilizing unused logCalled variables.

Multiple tests declare static bool logCalled = false and set up a console handler, but never assert on logCalled. If console output verification is needed, add assertions; otherwise, consider removing these unused variables to reduce noise.

Also applies to: 30-32, 44-46, 70-72, 97-99, 114-116, 133-135

bridge/core/css/style_engine.cc (2)

1156-1166: Consider consolidating display:none detection.

The detection logic first attempts GetPropertyCSSValue with identifier check, then falls back to string comparison. This is reasonable but could be extracted to a helper function since it's duplicated in RecalcStyleForElementOnly (lines 1546-1557).


1505-1869: Consider extracting shared logic between RecalcStyleForSubtree and RecalcStyleForElementOnly.

The apply_for_element logic in RecalcStyleForSubtree (lines 1138-1480) is nearly identical to the body of RecalcStyleForElementOnly (lines 1529-1866). This significant duplication increases maintenance burden and risk of divergence.

Consider extracting the per-element styling logic into a shared helper method.

♻️ Suggested approach
// Private helper that applies sheet/pseudo styles for a single element.
// Returns true if element has display:none (indicating subtree skip).
bool StyleEngine::ApplyStylesForElement(Element* element,
                                        StyleResolver& resolver,
                                        UICommandBuffer* command_buffer,
                                        bool emit_before,
                                        bool emit_after,
                                        bool emit_first_letter,
                                        bool emit_first_line);

Then both RecalcStyleForSubtree and RecalcStyleForElementOnly can call this helper, reducing ~700 lines of duplication.

webf/lib/src/dom/element.dart (1)

2331-2370: Robust parsing but potential duplication with inline logic.

The _normalizeInlineStyleEntryFromNative method correctly handles:

  • Quoted strings and nested function calls (lines 2338-2363)
  • Trailing !important detection with depth tracking
  • Proper extraction and trimming

However, similar (simpler) parsing logic exists in setInlineStyle (lines 2027-2047) and setSheetStyle (lines 2104-2124). Consider whether these inline blocks should delegate to this helper for consistency.

♻️ Potential consolidation

Both setInlineStyle and setSheetStyle contain inline !important parsing. Consider refactoring to use _normalizeInlineStyleEntryFromNative in those locations for consistency, as this method is more robust (handles quotes and nested calls).

For example, in setInlineStyle around line 2027:

-    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) {
+    if (fromNative) {
       entry = _normalizeInlineStyleEntryFromNative(entry);
+      derivedImportant = entry.important;
+      derivedValue = entry.value;
     }

Similarly for setSheetStyle.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 978c974 and 4e53ae7.

⛔ Files ignored due to path filters (1)
  • integration_tests/snapshots/css/css-flexbox/relayout-align-to-stretch.ts.f379be341.png is excluded by !**/*.png
📒 Files selected for processing (63)
  • bridge/bindings/qjs/converter_impl.h
  • bridge/core/api/element.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/core/css/css_properties.json5
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/core/css/resolver/cascade_map.cc
  • bridge/core/css/resolver/cascade_map.h
  • bridge/core/css/resolver/style_cascade.cc
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/css/resolver/style_resolver.h
  • bridge/core/css/rule_feature_set.cc
  • bridge/core/css/rule_feature_set.h
  • bridge/core/css/style_engine.cc
  • bridge/core/css/style_engine.h
  • bridge/core/dom/element.cc
  • bridge/core/dom/element.d.ts
  • bridge/core/dom/element.h
  • bridge/core/dom/legacy/element_attributes.cc
  • bridge/core/frame/window.cc
  • bridge/foundation/native_type.h
  • bridge/foundation/shared_ui_command.cc
  • bridge/foundation/shared_ui_command.h
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/foundation/ui_command_buffer.cc
  • bridge/foundation/ui_command_buffer.h
  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/ui_command_strategy.cc
  • bridge/foundation/ui_command_strategy_test.cc
  • bridge/test/css_unittests.cmake
  • bridge/test/webf_test_context.cc
  • integration_tests/specs/css/css-inline/important-semantics.ts
  • integration_tests/specs/css/css-transforms/translate.ts
  • webf/example/lib/main.dart
  • webf/lib/src/bridge/native_types.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/css/animation.dart
  • webf/lib/src/css/computed_style_declaration.dart
  • webf/lib/src/css/css_animation.dart
  • webf/lib/src/css/element_rule_collector.dart
  • webf/lib/src/css/parser/parser.dart
  • webf/lib/src/css/rule_set.dart
  • webf/lib/src/css/style_declaration.dart
  • webf/lib/src/devtools/cdp_service/modules/css.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/lib/src/html/svg.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/widget/widget_element.dart
  • webf/test/local_http_server.dart
  • webf/test/src/css/background_shorthand_clip_text_test.dart
  • webf/test/src/css/css_wide_keywords_inherit_test.dart
  • webf/test/src/css/inline_style_important_from_native_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inset_shorthand_test.dart
  • webf/test/src/css/style_declaration_merge_union_test.dart
  • webf/test/src/css/style_inline_parser.dart
  • webf/test/src/rendering/css_sizing_test.dart
💤 Files with no reviewable changes (2)
  • webf/test/src/css/background_shorthand_clip_text_test.dart
  • webf/test/src/css/css_wide_keywords_inherit_test.dart
✅ Files skipped from review due to trivial changes (1)
  • bridge/core/css/resolver/cascade_map.cc
🚧 Files skipped from review as they are similar to previous changes (23)
  • bridge/core/css/css_properties.json5
  • bridge/foundation/native_type.h
  • webf/lib/src/css/css_animation.dart
  • webf/test/src/rendering/css_sizing_test.dart
  • bridge/core/css/resolver/cascade_map.h
  • webf/lib/src/css/computed_style_declaration.dart
  • webf/lib/src/html/svg.dart
  • webf/lib/src/devtools/cdp_service/modules/css.dart
  • bridge/core/dom/legacy/element_attributes.cc
  • webf/test/src/css/style_declaration_merge_union_test.dart
  • bridge/foundation/shared_ui_command.h
  • integration_tests/specs/css/css-inline/important-semantics.ts
  • webf/lib/src/widget/widget_element.dart
  • webf/test/src/css/inline_style_important_from_native_test.dart
  • bridge/core/api/element.cc
  • bridge/core/css/rule_feature_set.h
  • bridge/foundation/ui_command_strategy.cc
  • integration_tests/specs/css/css-transforms/translate.ts
  • bridge/foundation/ui_command_buffer.cc
  • webf/lib/src/bridge/native_types.dart
  • bridge/core/frame/window.cc
  • webf/lib/src/css/element_rule_collector.dart
  • webf/lib/src/css/rule_set.dart
🧰 Additional context used
📓 Path-based instructions (12)
webf/**/*.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

webf/**/*.dart: Follow rules in webf/analysis_options.yaml for Dart code style
Use single quotes for strings in Dart code
File names must use snake_case in Dart
Class names must use PascalCase in Dart
Variables and functions must use camelCase in Dart
Prefer final fields when applicable in Dart code
Lines should be max 120 characters in Dart code
Always free allocated memory in Dart FFI using malloc.free() for toNativeUtf8() allocations
Free FFI allocated memory in finally blocks to ensure cleanup on exceptions
Track ownership of allocated pointers in FFI callbacks
Free NativeValue pointers after converting with fromNativeValue in FFI code
Document memory ownership clearly in FFI async callbacks
Implement WidgetElement to create custom Flutter widgets integrated into WebF's DOM tree
Register custom WidgetElements using WidgetElementRegistry.register(tagName, builder)
Override buildWidget(BuildContext context) method in WidgetElement to build the Flutter widget
Call updateWidget() when attributes change in WidgetElement implementations
Dispose controllers and subscriptions in WidgetElement for memory management
Follow W3C event standards when dispatching events from WidgetElement
Minimize widget rebuilds in WidgetElement for performance optimization
Implement ARIA attributes in WidgetElement when applicable for accessibility

Dart code in webf module must follow naming conventions: snake_case for file names, PascalCase for classes, and camelCase for class members

webf/**/*.dart: Always free allocated memory in Dart FFI
Use malloc.free() for toNativeUtf8() allocations in Dart FFI
Track pointer ownership in callbacks within Dart FFI

Files:

  • webf/lib/src/css/animation.dart
  • webf/example/lib/main.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/test/src/css/style_inline_parser.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/test/local_http_server.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/css/parser/parser.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/bridge/ui_command.dart
  • webf/test/src/css/inset_shorthand_test.dart
  • webf/lib/src/css/style_declaration.dart
webf/lib/src/css/**/*.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

Use CSSRenderStyle for style computation and storage in Dart CSS code

Files:

  • webf/lib/src/css/animation.dart
  • webf/lib/src/css/parser/parser.dart
  • webf/lib/src/css/style_declaration.dart
{bridge/**/*.{cc,h},webf/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

Document memory ownership clearly in FFI implementations

Files:

  • webf/lib/src/css/animation.dart
  • bridge/core/dom/element.h
  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/shared_ui_command_test.cc
  • webf/example/lib/main.dart
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/rule_feature_set.cc
  • webf/lib/src/bridge/to_native.dart
  • bridge/test/webf_test_context.cc
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/style_engine.cc
  • webf/test/src/css/style_inline_parser.dart
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • bridge/foundation/ui_command_strategy_test.cc
  • bridge/core/css/style_engine.h
  • webf/lib/src/html/form/base_input.dart
  • webf/test/local_http_server.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/lib/src/launcher/view_controller.dart
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/foundation/shared_ui_command.cc
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • bridge/bindings/qjs/converter_impl.h
  • webf/lib/src/css/parser/parser.dart
  • bridge/foundation/ui_command_buffer.h
  • webf/lib/src/dom/element.dart
  • bridge/core/css/resolver/style_cascade.cc
  • webf/lib/src/bridge/ui_command.dart
  • bridge/core/css/blink_inline_style_validation_test.cc
  • webf/test/src/css/inset_shorthand_test.dart
  • bridge/core/css/resolver/style_resolver.h
  • webf/lib/src/css/style_declaration.dart
bridge/**/*.{cc,cpp,h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{cc,cpp,h,hpp}: C++ code should follow Chromium style (.clang-format) with C++17 standard, 120 character column limit, and 2-space indentation
Use WEBF_EXPORT_C macro for exporting C functions to Dart FFI
In FFI contexts, use Dart_Handle instead of Handle for type compatibility
For C++ FFI function naming: use GetObjectPropertiesFromDart for C++ exports, NativeGetObjectPropertiesFunc for Dart typedefs, and GetObjectPropertiesFunc for Dart functions
Lambda signatures in C++ must match expected function signatures to avoid FFI type mismatches
Choose power-of-2 buffer sizes (512, 1024, 2048) for ring buffer implementation, with smaller sizes for DEBUG_BUILD, MOBILE constraints, and larger sizes for DESKTOP performance

Files:

  • bridge/core/dom/element.h
  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/rule_feature_set.cc
  • bridge/test/webf_test_context.cc
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/style_engine.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • bridge/foundation/ui_command_strategy_test.cc
  • bridge/core/css/style_engine.h
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/foundation/shared_ui_command.cc
  • bridge/bindings/qjs/converter_impl.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/css/resolver/style_cascade.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/core/css/resolver/style_resolver.h
bridge/**/*.{h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{h,hpp}: Ring buffer command structure should use enum Type : uint8_t for command types with union for type-specific data to ensure type-safe and cache-friendly command handling
Ring buffer implementation should use alignas(64) for atomic head and tail pointers, std::atomic<size_t> for thread-safe synchronization, and power-of-2 buffer sizes enforced with static_assert

Files:

  • bridge/core/dom/element.h
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/style_engine.h
  • bridge/bindings/qjs/converter_impl.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/css/resolver/style_resolver.h
bridge/**/*.{cc,h}

📄 CodeRabbit inference engine (AGENTS.md)

C++ code in bridge module must use C++17 standard with 2-space indentation, 120 column limit, and follow Chromium style guide as defined in .clang-format

bridge/**/*.{cc,h}: Use RAII patterns in C++ where possible for resource management
Use PostToJs for executing operations on the JS thread in FFI
Use PostToDart for returning results to Dart isolate
Avoid PostToJsSync synchronous execution when possible

C++ bridge code must use 2-space indent, 120 column line limit, and follow Chromium style via .clang-format

Files:

  • bridge/core/dom/element.h
  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/rule_feature_set.cc
  • bridge/test/webf_test_context.cc
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/style_engine.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • bridge/foundation/ui_command_strategy_test.cc
  • bridge/core/css/style_engine.h
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/foundation/shared_ui_command.cc
  • bridge/bindings/qjs/converter_impl.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/css/resolver/style_cascade.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/core/css/resolver/style_resolver.h
bridge/core/**

📄 CodeRabbit inference engine (bridge/AGENTS.md)

Core bridge code should be located in bridge/core/ directory

Files:

  • bridge/core/dom/element.h
  • bridge/core/dom/element.d.ts
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/rule_feature_set.cc
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/style_engine.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • bridge/core/css/style_engine.h
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/core/css/resolver/style_cascade.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/core/css/resolver/style_resolver.h
bridge/**/*.{cc,cpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{cc,cpp}: For async FFI operations, use Dart_NewPersistentHandle_DL to keep Dart objects alive, convert back with Dart_HandleFromPersistent_DL before use, and always call Dart_DeletePersistentHandle_DL after the async operation completes
For string handling in FFI, copy strings that might be freed using std::string(const_char_ptr), and use toNativeUtf8() with proper memory deallocation
For async callbacks with potential errors, always provide error path in callbacks (e.g., callback(object, nullptr)), handle cancellation cases in async operations, and propagate errors through callback parameters rather than exceptions
For thread-safe error reporting in FFI, copy error messages before crossing thread boundaries using std::string to ensure string lifetime, and consider error callbacks separate from result callbacks
Avoid PostToJsSync when threads may interdepend to prevent synchronous deadlocks in FFI communication
Ensure callback functions aren't invoked after context destruction to prevent use-after-free errors in FFI async operations
Implement ring buffer overflow handling with metrics and alerts to monitor command buffer capacity
Process multiple UI commands per frame in a loop with a MAX_COMMANDS_PER_FRAME limit to balance responsiveness and performance
Pin threads to cores for optimal cache usage in ring buffer operations by setting CPU affinity for UI threads
Use PostToJs for executing operations on the JS thread from other threads, PostToDart for returning results to Dart isolate, and avoid PostToJsSync to prevent deadlocks

Files:

  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.cc
  • bridge/core/css/rule_feature_set.cc
  • bridge/test/webf_test_context.cc
  • bridge/core/css/inline_css_style_declaration_test.cc
  • bridge/core/css/style_engine.cc
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • bridge/foundation/ui_command_strategy_test.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/foundation/shared_ui_command.cc
  • bridge/core/css/resolver/style_cascade.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
bridge/test/**/*.{cc,cpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

Add bridge unit test files to bridge/test/ directory and use Google Test macros: TEST(), EXPECT_EQ(), etc. Tests are automatically discovered by CMake

Files:

  • bridge/test/webf_test_context.cc
bridge/test/**/*.{cc,h}

📄 CodeRabbit inference engine (AGENTS.md)

Bridge unit tests must be added under bridge/test/ and use Google Test framework

Bridge unit tests must use GoogleTest framework, keep tests small and behavior-focused, and mirror source paths under bridge/test/

Files:

  • bridge/test/webf_test_context.cc
webf/test/**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Dart/Flutter widget and unit tests must be placed in webf/test/ and use WebFWidgetTestUtils and pumpAndSettle() where needed

Files:

  • webf/test/src/css/style_inline_parser.dart
  • webf/test/local_http_server.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/test/src/css/inset_shorthand_test.dart
webf/test/**/*_test.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

webf/test/**/*_test.dart: Use WebFWidgetTestUtils.prepareWidgetTest() to test HTML/CSS rendering in widget unit tests
Access render objects in tests to verify layout calculations
Call setupTest() in setUpAll() method for one-time setup in unit tests
When testing with WebFController, wait for initialization with: await controller.controlledInitCompleter.future
Use mock bundles from test/src/foundation/mock_bundle.dart for testing in unit tests

Files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/test/src/css/inset_shorthand_test.dart
🧠 Learnings (55)
📓 Common learnings
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/lib/src/css/**/*.dart : Use CSSRenderStyle for style computation and storage in Dart CSS code
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: CSS property implementations are located in lib/src/css/
Learnt from: CR
Repo: openwebf/webf PR: 0
File: scripts/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:41.357Z
Learning: Applies to scripts/bridge/core/**/*.d.ts : Transform WebF-specific type annotations: `DartImpl<T>` → `T`, `StaticMember<T>` → `T`, `StaticMethod<T>` → `T`, `SupportAsync<T>` → generates both sync and async variants, `DependentsOnLayout<T>` → `T`
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/lib/src/css/**/*.dart : Use CSSRenderStyle for style computation and storage in Dart CSS code

Applied to files:

  • webf/lib/src/css/animation.dart
  • bridge/core/dom/element.d.ts
  • webf/lib/src/bridge/to_native.dart
  • bridge/core/css/style_engine.cc
  • webf/test/src/css/style_inline_parser.dart
  • bridge/core/css/resolver/style_resolver.cc
  • bridge/core/dom/element.cc
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • bridge/bindings/qjs/converter_impl.h
  • webf/lib/src/css/parser/parser.dart
  • webf/lib/src/dom/element.dart
  • bridge/core/css/resolver/style_cascade.cc
  • webf/lib/src/bridge/ui_command.dart
  • bridge/core/css/blink_inline_style_validation_test.cc
  • webf/test/src/css/inset_shorthand_test.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Follow rules in webf/analysis_options.yaml for Dart code style

Applied to files:

  • webf/lib/src/css/animation.dart
  • webf/example/lib/main.dart
  • webf/test/src/css/style_inline_parser.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/css/parser/parser.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: No build needed for Dart-only changes in webf/

Applied to files:

  • webf/lib/src/css/animation.dart
  • webf/example/lib/main.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Minimize widget rebuilds in WidgetElement for performance optimization

Applied to files:

  • webf/lib/src/css/animation.dart
  • webf/example/lib/main.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:11.651Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-08T23:28:11.651Z
Learning: Applies to bridge/**/*.{cc,h} : C++ code in bridge module must use C++17 standard with 2-space indentation, 120 column limit, and follow Chromium style guide as defined in `.clang-format`

Applied to files:

  • bridge/core/dom/element.h
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/dom/element.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : C++ code should follow Chromium style (.clang-format) with C++17 standard, 120 character column limit, and 2-space indentation

Applied to files:

  • bridge/core/dom/element.h
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/css/style_engine.cc
  • bridge/core/dom/element.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-21T14:42:52.637Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/AGENTS.md:0-0
Timestamp: 2025-12-21T14:42:52.637Z
Learning: Applies to bridge/**/*.{cc,h} : C++ bridge code must use 2-space indent, 120 column line limit, and follow Chromium style via `.clang-format`

Applied to files:

  • bridge/core/dom/element.h
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/core/dom/element.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Implement WidgetElement to create custom Flutter widgets integrated into WebF's DOM tree

Applied to files:

  • bridge/core/dom/element.h
  • bridge/core/dom/element.d.ts
  • webf/example/lib/main.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp} : Process multiple UI commands per frame in a loop with a MAX_COMMANDS_PER_FRAME limit to balance responsiveness and performance

Applied to files:

  • bridge/foundation/ui_command_ring_buffer_test.cc
  • bridge/foundation/shared_ui_command_test.cc
  • bridge/foundation/ui_command_strategy_test.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp} : Implement ring buffer overflow handling with metrics and alerts to monitor command buffer capacity

Applied to files:

  • bridge/foundation/ui_command_ring_buffer_test.cc
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.{cpp,h,hpp} : Use RAII patterns in C++ where possible for memory management

Applied to files:

  • bridge/foundation/ui_command_ring_buffer_test.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/test/**/*.{cc,cpp} : Add bridge unit test files to `bridge/test/` directory and use Google Test macros: `TEST()`, `EXPECT_EQ()`, etc. Tests are automatically discovered by CMake

Applied to files:

  • bridge/foundation/shared_ui_command_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: scripts/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:41.357Z
Learning: Applies to scripts/bridge/core/**/*.d.ts : Transform WebF-specific type annotations: `DartImpl<T>` → `T`, `StaticMember<T>` → `T`, `StaticMethod<T>` → `T`, `SupportAsync<T>` → generates both sync and async variants, `DependentsOnLayout<T>` → `T`

Applied to files:

  • bridge/core/dom/element.d.ts
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/bridge/ui_command.dart
  • bridge/core/css/blink_inline_style_validation_test.cc
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: scripts/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:41.357Z
Learning: Applies to scripts/bridge/core/**/*.d.ts : DO NOT manually edit `bridge/typings/webf.d.ts` - it is generated from bridge/core/*.d.ts

Applied to files:

  • bridge/core/dom/element.d.ts
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Prefer final fields when applicable in Dart code

Applied to files:

  • webf/example/lib/main.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Document memory ownership clearly in FFI async callbacks

Applied to files:

  • webf/example/lib/main.dart
  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/test/**/*_test.dart : When testing with WebFController, wait for initialization with: await controller.controlledInitCompleter.future

Applied to files:

  • webf/example/lib/main.dart
  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to webf/**/*.dart : Track pointer ownership in callbacks within Dart FFI

Applied to files:

  • webf/example/lib/main.dart
  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Call updateWidget() when attributes change in WidgetElement implementations

Applied to files:

  • webf/example/lib/main.dart
  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/lib/src/dom/element.dart
  • webf/test/src/css/inset_shorthand_test.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Variables and functions must use camelCase in Dart

Applied to files:

  • webf/example/lib/main.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to docs/**/*.md : Include WebFControllerManager setup in code examples within documentation

Applied to files:

  • webf/example/lib/main.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/lib/bridge.dart : lib/bridge.dart contains FFI bindings to C++ bridge

Applied to files:

  • webf/lib/src/bridge/to_native.dart
  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp} : Avoid `PostToJsSync` when threads may interdepend to prevent synchronous deadlocks in FFI communication

Applied to files:

  • bridge/test/webf_test_context.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to bridge/**/*.{cc,h} : Avoid `PostToJsSync` synchronous execution when possible

Applied to files:

  • bridge/test/webf_test_context.cc
  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to bridge/**/*.{cc,h} : Use `PostToJs` for executing operations on the JS thread in FFI

Applied to files:

  • bridge/core/css/legacy/legacy_inline_css_style_declaration.h
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Implement ARIA attributes in WidgetElement when applicable for accessibility

Applied to files:

  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/html/grouping_content.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/lib/src/rendering/**/*.dart : Use RenderBoxModel as base class for layout in Dart rendering code

Applied to files:

  • webf/lib/src/html/form/base_input.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Follow W3C event standards when dispatching events from WidgetElement

Applied to files:

  • webf/lib/src/html/form/base_input.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to bridge/**/*.{cc,h} : Use `PostToDart` for returning results to Dart isolate

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to webf/**/*.dart : Use `malloc.free()` for `toNativeUtf8()` allocations in Dart FFI

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to webf/**/*.dart : Always free allocated memory in Dart FFI

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp} : For async FFI operations, use `Dart_NewPersistentHandle_DL` to keep Dart objects alive, convert back with `Dart_HandleFromPersistent_DL` before use, and always call `Dart_DeletePersistentHandle_DL` after the async operation completes

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Track ownership of allocated pointers in FFI callbacks

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Always free allocated memory in Dart FFI using malloc.free() for toNativeUtf8() allocations

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Free FFI allocated memory in finally blocks to ensure cleanup on exceptions

Applied to files:

  • webf/test/local_http_server.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/test/**/*_test.dart : Use WebFWidgetTestUtils.prepareWidgetTest() to test HTML/CSS rendering in widget unit tests

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/test/src/css/inset_shorthand_test.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Use widget unit tests to verify rendering changes with: cd webf && flutter test test/src/rendering/

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • webf/test/src/css/inset_shorthand_test.dart
📚 Learning: 2025-12-08T23:28:11.651Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-08T23:28:11.651Z
Learning: Applies to webf/test/**/*.dart : Dart/Flutter widget and unit tests must be placed in `webf/test/` and use `WebFWidgetTestUtils` and `pumpAndSettle()` where needed

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
📚 Learning: 2025-12-08T23:28:11.651Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-08T23:28:11.651Z
Learning: Applies to webf/integration_test/**/*.dart : Dart/Flutter integration tests must be placed in `webf/integration_test/` directory

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Run widget unit tests with: cd webf && flutter test test/src/rendering/

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/test/**/*_test.dart : Access render objects in tests to verify layout calculations

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
  • webf/test/src/css/inline_style_important_upgrade_same_value_test.dart
  • bridge/core/css/blink_inline_style_validation_test.cc
  • webf/test/src/css/inset_shorthand_test.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/integration_tests/specs/**/*.dart : Use snapshot tests in integration_tests/specs/ for visual regression testing with await snapshot()

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Run Flutter dart tests with: cd webf && flutter test

Applied to files:

  • webf/test/src/css/inline_style_remove_fallback_test.dart
📚 Learning: 2025-12-21T14:42:52.637Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/AGENTS.md:0-0
Timestamp: 2025-12-21T14:42:52.637Z
Learning: Applies to bridge/test/**/*.{cc,h} : Bridge unit tests must use GoogleTest framework, keep tests small and behavior-focused, and mirror source paths under `bridge/test/`

Applied to files:

  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/core/css/blink_inline_style_validation_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-08T23:28:11.651Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-08T23:28:11.651Z
Learning: Applies to bridge/test/**/*.{cc,h} : Bridge unit tests must be added under `bridge/test/` and use Google Test framework

Applied to files:

  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-26T09:18:25.075Z
Learnt from: CGQAQ
Repo: openwebf/webf PR: 777
File: integration_tests/specs/css/css-text-mixin/text_comprehensive_test.ts:389-391
Timestamp: 2025-12-26T09:18:25.075Z
Learning: In WebF integration tests, the background shorthand property syntax `background: <gradient> text` is valid CSS per MDN spec, where "text" is a valid background-clip value. The explicit backgroundClip assignment that follows is a workaround for WebF's current CSS parser limitation, not because the syntax is invalid.

Applied to files:

  • bridge/core/css/legacy/legacy_inline_css_style_declaration_test.cc
  • webf/test/src/css/inset_shorthand_test.dart
  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Override buildWidget(BuildContext context) method in WidgetElement to build the Flutter widget

Applied to files:

  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : Use `WEBF_EXPORT_C` macro for exporting C functions to Dart FFI

Applied to files:

  • webf/lib/src/bridge/ui_command.dart
  • bridge/core/css/blink_inline_style_validation_test.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp} : For string handling in FFI, copy strings that might be freed using `std::string(const_char_ptr)`, and use `toNativeUtf8()` with proper memory deallocation

Applied to files:

  • bridge/core/css/blink_inline_style_validation_test.cc
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T16:32:47.644Z
Learning: Applies to {bridge/**/*.{cc,h},webf/**/*.dart} : Document memory ownership clearly in FFI implementations

Applied to files:

  • bridge/core/css/blink_inline_style_validation_test.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : For C++ FFI function naming: use `GetObjectPropertiesFromDart` for C++ exports, `NativeGetObjectPropertiesFunc` for Dart typedefs, and `GetObjectPropertiesFunc` for Dart functions

Applied to files:

  • bridge/core/css/blink_inline_style_validation_test.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: bridge/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:27:15.946Z
Learning: Applies to bridge/ios/webf_ios.podspec : Ensure all source files, particularly `member_installer.cc`, are included in the `source_files` pattern in `ios/webf_ios.podspec`

Applied to files:

  • bridge/test/css_unittests.cmake
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: CSS property implementations are located in lib/src/css/

Applied to files:

  • webf/lib/src/css/style_declaration.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR
Repo: openwebf/webf PR: 0
File: webf/CLAUDE.md:0-0
Timestamp: 2025-12-08T23:28:00.818Z
Learning: Applies to webf/**/*.dart : Class names must use PascalCase in Dart

Applied to files:

  • webf/lib/src/css/style_declaration.dart
🧬 Code graph analysis (9)
bridge/core/dom/element.h (3)
bridge/core/css/css_property_value_set.cc (3)
  • MutableCSSPropertyValueSet (352-353)
  • MutableCSSPropertyValueSet (355-362)
  • MutableCSSPropertyValueSet (364-377)
bridge/core/css/legacy/legacy_inline_css_style_declaration.cc (1)
  • LegacyInlineCssStyleDeclaration (158-159)
bridge/core/dom/element.cc (2)
  • style (438-444)
  • style (438-438)
bridge/core/dom/element.d.ts (2)
bridge/core/dom/element.h (8)
  • Element (48-462)
  • Element (401-403)
  • Element (406-412)
  • Element (418-421)
  • Element (425-438)
  • Element (448-452)
  • Element (454-456)
  • Element (458-460)
bridge/core/css/legacy/legacy_inline_css_style_declaration.cc (1)
  • LegacyInlineCssStyleDeclaration (158-159)
bridge/core/css/style_engine.cc (4)
bridge/core/executing_context.cc (2)
  • ctx (509-512)
  • ctx (509-509)
bridge/core/css/invalidation/pending_invalidations_test.cc (1)
  • collector (218-218)
bridge/core/css/element_rule_collector.h (1)
  • PseudoElementStyleRequest (58-112)
bridge/core/css/properties/css_parsing_utils.cc (14)
  • value (268-307)
  • value (334-369)
  • value (424-516)
  • value (527-547)
  • value (586-624)
  • value (638-659)
  • value (662-673)
  • value (676-699)
  • value (724-745)
  • value (752-775)
  • value (873-891)
  • value (894-937)
  • value (945-949)
  • value (957-1036)
bridge/core/css/legacy/legacy_inline_css_style_declaration.h (3)
bridge/core/css/legacy/legacy_inline_css_style_declaration.cc (6)
  • InternalSetProperty (409-460)
  • InternalSetProperty (409-411)
  • InternalRemoveProperty (462-478)
  • InternalRemoveProperty (462-462)
  • InternalClearProperty (480-487)
  • InternalClearProperty (480-480)
bridge/core/css/legacy/legacy_css_style_declaration.h (3)
  • std (73-73)
  • std (74-75)
  • AtomicString (42-42)
bridge/core/css/css_style_declaration.h (1)
  • AtomicString (42-87)
bridge/core/css/resolver/style_resolver.cc (2)
bridge/core/css/element_rule_collector.cc (1)
  • context (224-224)
bridge/core/css/style_engine.cc (3)
  • evaluator (2133-2133)
  • collector (1144-1144)
  • collector (1535-1535)
bridge/foundation/ui_command_strategy_test.cc (1)
bridge/foundation/shared_ui_command_test.cc (1)
  • shared_command_ (50-53)
bridge/foundation/shared_ui_command.cc (5)
bridge/foundation/ui_command_buffer.cc (2)
  • AddSheetStyleByIdCommand (102-118)
  • AddSheetStyleByIdCommand (102-107)
bridge/foundation/native_type.h (2)
  • property_id (98-98)
  • important (89-89)
bridge/foundation/ui_command_ring_buffer_test.cc (1)
  • item (106-106)
bridge/foundation/ui_command_strategy.h (1)
  • item (68-68)
bridge/foundation/ui_command_ring_buffer.cc (1)
  • item (254-254)
bridge/foundation/ui_command_buffer.h (3)
bridge/foundation/shared_ui_command.cc (2)
  • AddSheetStyleByIdCommand (94-116)
  • AddSheetStyleByIdCommand (94-99)
bridge/foundation/ui_command_buffer.cc (2)
  • AddSheetStyleByIdCommand (102-118)
  • AddSheetStyleByIdCommand (102-107)
bridge/foundation/native_type.h (2)
  • property_id (98-98)
  • important (89-89)
bridge/core/css/blink_inline_style_validation_test.cc (5)
bridge/core/css/legacy/legacy_inline_css_style_declaration.cc (2)
  • item (161-200)
  • item (161-161)
bridge/foundation/ui_command_ring_buffer_test.cc (1)
  • item (106-106)
bridge/foundation/ui_command_strategy.h (1)
  • item (68-68)
bridge/foundation/ui_command_ring_buffer.cc (1)
  • item (254-254)
bridge/test/webf_test_env.cc (2)
  • TEST_runLoop (331-337)
  • TEST_runLoop (331-331)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build_windows_bridge (Debug)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (rust)
  • GitHub Check: build_windows_bridge (Debug)

@CGQAQ CGQAQ force-pushed the fix/css-important-semantics branch from 4e53ae7 to a6098af Compare January 9, 2026 13:45
@CGQAQ CGQAQ changed the title fix/css important semantics fix: css important semantics Jan 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants