@@ -122,6 +122,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
122122 _pseudoBeforeStyle = newStyle;
123123 target? .markBeforePseudoElementNeedsUpdate ();
124124 }
125+
125126 CSSStyleDeclaration ? get resolvedPseudoBeforeStyle =>
126127 _resolvePseudoStyle (_pseudoBeforeStyle, _inlinePseudoBeforeStyle);
127128
@@ -132,6 +133,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
132133 _pseudoAfterStyle = newStyle;
133134 target? .markAfterPseudoElementNeedsUpdate ();
134135 }
136+
135137 CSSStyleDeclaration ? get resolvedPseudoAfterStyle =>
136138 _resolvePseudoStyle (_pseudoAfterStyle, _inlinePseudoAfterStyle);
137139
@@ -144,6 +146,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
144146 // Trigger a layout rebuild so IFC can re-shape text for first-letter styling
145147 target? .markFirstLetterPseudoNeedsUpdate ();
146148 }
149+
147150 CSSStyleDeclaration ? get resolvedPseudoFirstLetterStyle =>
148151 _resolvePseudoStyle (
149152 _pseudoFirstLetterStyle, _inlinePseudoFirstLetterStyle);
@@ -156,6 +159,7 @@ class CSSStyleDeclaration extends DynamicBindingObject
156159 _pseudoFirstLineStyle = newStyle;
157160 target? .markFirstLinePseudoNeedsUpdate ();
158161 }
162+
159163 CSSStyleDeclaration ? get resolvedPseudoFirstLineStyle =>
160164 _resolvePseudoStyle (_pseudoFirstLineStyle, _inlinePseudoFirstLineStyle);
161165
@@ -567,14 +571,16 @@ class CSSStyleDeclaration extends DynamicBindingObject
567571
568572 // Validate value.
569573 switch (propertyName) {
570- case GAP : {
571- final List <String > tokens = splitByAsciiWhitespacePreservingGroups (normalizedValue);
572- if (tokens.isEmpty || tokens.length > 2 ) return false ;
573- for (final token in tokens) {
574- if (! CSSGap .isValidGapValue (token)) return false ;
574+ case GAP :
575+ {
576+ final List <String > tokens =
577+ splitByAsciiWhitespacePreservingGroups (normalizedValue);
578+ if (tokens.isEmpty || tokens.length > 2 ) return false ;
579+ for (final token in tokens) {
580+ if (! CSSGap .isValidGapValue (token)) return false ;
581+ }
582+ break ;
575583 }
576- break ;
577- }
578584 case ROW_GAP :
579585 case COLUMN_GAP :
580586 if (! CSSGap .isValidGapValue (normalizedValue)) return false ;
@@ -1017,34 +1023,26 @@ class CSSStyleDeclaration extends DynamicBindingObject
10171023
10181024 if (beforeRules.isNotEmpty) {
10191025 pseudoBeforeStyle = cascadeMatchedStyleRules (beforeRules);
1020- parentElement.markBeforePseudoElementNeedsUpdate ();
10211026 } else if (beforeRules.isEmpty && pseudoBeforeStyle != null ) {
10221027 pseudoBeforeStyle = null ;
1023- parentElement.markBeforePseudoElementNeedsUpdate ();
10241028 }
10251029
10261030 if (afterRules.isNotEmpty) {
10271031 pseudoAfterStyle = cascadeMatchedStyleRules (afterRules);
1028- parentElement.markAfterPseudoElementNeedsUpdate ();
10291032 } else if (afterRules.isEmpty && pseudoAfterStyle != null ) {
10301033 pseudoAfterStyle = null ;
1031- parentElement.markAfterPseudoElementNeedsUpdate ();
10321034 }
10331035
10341036 if (firstLetterRules.isNotEmpty) {
10351037 pseudoFirstLetterStyle = cascadeMatchedStyleRules (firstLetterRules);
1036- parentElement.markFirstLetterPseudoNeedsUpdate ();
10371038 } else if (firstLetterRules.isEmpty && pseudoFirstLetterStyle != null ) {
10381039 pseudoFirstLetterStyle = null ;
1039- parentElement.markFirstLetterPseudoNeedsUpdate ();
10401040 }
10411041
10421042 if (firstLineRules.isNotEmpty) {
10431043 pseudoFirstLineStyle = cascadeMatchedStyleRules (firstLineRules);
1044- parentElement.markFirstLinePseudoNeedsUpdate ();
10451044 } else if (firstLineRules.isEmpty && pseudoFirstLineStyle != null ) {
10461045 pseudoFirstLineStyle = null ;
1047- parentElement.markFirstLinePseudoNeedsUpdate ();
10481046 }
10491047 }
10501048
@@ -1054,6 +1052,27 @@ class CSSStyleDeclaration extends DynamicBindingObject
10541052 ..addAll (_properties)
10551053 ..addAll (_pendingProperties);
10561054 bool updateStatus = false ;
1055+
1056+ void mergePseudoStyle ({
1057+ required CSSStyleDeclaration ? currentStyle,
1058+ required CSSStyleDeclaration ? incomingStyle,
1059+ required void Function (CSSStyleDeclaration ? value) assign,
1060+ required VoidCallback markNeedsUpdate,
1061+ required bool clearWhenMissing,
1062+ }) {
1063+ if (incomingStyle != null ) {
1064+ if (currentStyle == null ) {
1065+ final CSSStyleDeclaration mergedStyle = CSSStyleDeclaration ();
1066+ mergedStyle.merge (incomingStyle);
1067+ assign (mergedStyle);
1068+ } else if (currentStyle.merge (incomingStyle)) {
1069+ markNeedsUpdate ();
1070+ }
1071+ } else if (clearWhenMissing && currentStyle != null ) {
1072+ assign (null );
1073+ }
1074+ }
1075+
10571076 for (String propertyName in properties.keys) {
10581077 CSSPropertyValue ? prevValue = properties[propertyName];
10591078 CSSPropertyValue ? currentValue = other._pendingProperties[propertyName];
@@ -1091,50 +1110,63 @@ class CSSStyleDeclaration extends DynamicBindingObject
10911110 // 'other' are not dropped when this side is null. When pseudo rules were
10921111 // processed on the other side, clear stale pseudo styles if no rule matches.
10931112 if (other._didProcessPseudoRules) {
1094- if (other.pseudoBeforeStyle != null ) {
1095- pseudoBeforeStyle ?? = CSSStyleDeclaration ();
1096- pseudoBeforeStyle! .merge (other.pseudoBeforeStyle! );
1097- } else if (pseudoBeforeStyle != null ) {
1098- pseudoBeforeStyle = null ;
1099- }
1100-
1101- if (other.pseudoAfterStyle != null ) {
1102- pseudoAfterStyle ?? = CSSStyleDeclaration ();
1103- pseudoAfterStyle! .merge (other.pseudoAfterStyle! );
1104- } else if (pseudoAfterStyle != null ) {
1105- pseudoAfterStyle = null ;
1106- }
1107-
1108- if (other.pseudoFirstLetterStyle != null ) {
1109- pseudoFirstLetterStyle ?? = CSSStyleDeclaration ();
1110- pseudoFirstLetterStyle! .merge (other.pseudoFirstLetterStyle! );
1111- } else if (pseudoFirstLetterStyle != null ) {
1112- pseudoFirstLetterStyle = null ;
1113- }
1114-
1115- if (other.pseudoFirstLineStyle != null ) {
1116- pseudoFirstLineStyle ?? = CSSStyleDeclaration ();
1117- pseudoFirstLineStyle! .merge (other.pseudoFirstLineStyle! );
1118- } else if (pseudoFirstLineStyle != null ) {
1119- pseudoFirstLineStyle = null ;
1120- }
1113+ mergePseudoStyle (
1114+ currentStyle: pseudoBeforeStyle,
1115+ incomingStyle: other.pseudoBeforeStyle,
1116+ assign: (value) => pseudoBeforeStyle = value,
1117+ markNeedsUpdate: () => target? .markBeforePseudoElementNeedsUpdate (),
1118+ clearWhenMissing: true ,
1119+ );
1120+ mergePseudoStyle (
1121+ currentStyle: pseudoAfterStyle,
1122+ incomingStyle: other.pseudoAfterStyle,
1123+ assign: (value) => pseudoAfterStyle = value,
1124+ markNeedsUpdate: () => target? .markAfterPseudoElementNeedsUpdate (),
1125+ clearWhenMissing: true ,
1126+ );
1127+ mergePseudoStyle (
1128+ currentStyle: pseudoFirstLetterStyle,
1129+ incomingStyle: other.pseudoFirstLetterStyle,
1130+ assign: (value) => pseudoFirstLetterStyle = value,
1131+ markNeedsUpdate: () => target? .markFirstLetterPseudoNeedsUpdate (),
1132+ clearWhenMissing: true ,
1133+ );
1134+ mergePseudoStyle (
1135+ currentStyle: pseudoFirstLineStyle,
1136+ incomingStyle: other.pseudoFirstLineStyle,
1137+ assign: (value) => pseudoFirstLineStyle = value,
1138+ markNeedsUpdate: () => target? .markFirstLinePseudoNeedsUpdate (),
1139+ clearWhenMissing: true ,
1140+ );
11211141 } else {
1122- if (other.pseudoBeforeStyle != null ) {
1123- pseudoBeforeStyle ?? = CSSStyleDeclaration ();
1124- pseudoBeforeStyle! .merge (other.pseudoBeforeStyle! );
1125- }
1126- if (other.pseudoAfterStyle != null ) {
1127- pseudoAfterStyle ?? = CSSStyleDeclaration ();
1128- pseudoAfterStyle! .merge (other.pseudoAfterStyle! );
1129- }
1130- if (other.pseudoFirstLetterStyle != null ) {
1131- pseudoFirstLetterStyle ?? = CSSStyleDeclaration ();
1132- pseudoFirstLetterStyle! .merge (other.pseudoFirstLetterStyle! );
1133- }
1134- if (other.pseudoFirstLineStyle != null ) {
1135- pseudoFirstLineStyle ?? = CSSStyleDeclaration ();
1136- pseudoFirstLineStyle! .merge (other.pseudoFirstLineStyle! );
1137- }
1142+ mergePseudoStyle (
1143+ currentStyle: pseudoBeforeStyle,
1144+ incomingStyle: other.pseudoBeforeStyle,
1145+ assign: (value) => pseudoBeforeStyle = value,
1146+ markNeedsUpdate: () => target? .markBeforePseudoElementNeedsUpdate (),
1147+ clearWhenMissing: false ,
1148+ );
1149+ mergePseudoStyle (
1150+ currentStyle: pseudoAfterStyle,
1151+ incomingStyle: other.pseudoAfterStyle,
1152+ assign: (value) => pseudoAfterStyle = value,
1153+ markNeedsUpdate: () => target? .markAfterPseudoElementNeedsUpdate (),
1154+ clearWhenMissing: false ,
1155+ );
1156+ mergePseudoStyle (
1157+ currentStyle: pseudoFirstLetterStyle,
1158+ incomingStyle: other.pseudoFirstLetterStyle,
1159+ assign: (value) => pseudoFirstLetterStyle = value,
1160+ markNeedsUpdate: () => target? .markFirstLetterPseudoNeedsUpdate (),
1161+ clearWhenMissing: false ,
1162+ );
1163+ mergePseudoStyle (
1164+ currentStyle: pseudoFirstLineStyle,
1165+ incomingStyle: other.pseudoFirstLineStyle,
1166+ assign: (value) => pseudoFirstLineStyle = value,
1167+ markNeedsUpdate: () => target? .markFirstLinePseudoNeedsUpdate (),
1168+ clearWhenMissing: false ,
1169+ );
11381170 }
11391171
11401172 return updateStatus;
0 commit comments