we (web engine): Experimental web browser project to understand the limits of Claude

Fix gap direction for column flex containers

Per CSS Box Alignment §8, row-gap applies between rows and column-gap
between columns. In a column flex container, the main axis is vertical
so row-gap should be used for main-axis spacing and column-gap for
cross-axis spacing. Previously the code always used column-gap for
main-axis and row-gap for cross-axis regardless of direction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+19 -12
+19 -12
crates/layout/src/lib.rs
··· 897 897 let justify_content = parent.justify_content; 898 898 let align_items = parent.align_items; 899 899 let align_content = parent.align_content; 900 - let row_gap = parent.row_gap; 901 - let column_gap = parent.column_gap; 902 - 903 900 let container_main_size = match flex_direction { 904 901 FlexDirection::Row | FlexDirection::RowReverse => parent.rect.width, 905 902 FlexDirection::Column | FlexDirection::ColumnReverse => { ··· 927 924 flex_direction, 928 925 FlexDirection::RowReverse | FlexDirection::ColumnReverse 929 926 ); 927 + 928 + // Per CSS Box Alignment §8, row-gap applies between rows and column-gap 929 + // between columns. In a row flex container the main axis is horizontal 930 + // (column-gap between items, row-gap between lines). In a column flex 931 + // container the axes are swapped. 932 + let (main_gap, cross_gap) = if is_row { 933 + (parent.column_gap, parent.row_gap) 934 + } else { 935 + (parent.row_gap, parent.column_gap) 936 + }; 930 937 931 938 if parent.children.is_empty() { 932 939 parent.rect.height = 0.0; ··· 1070 1077 let gap = if current_line.is_empty() { 1071 1078 0.0 1072 1079 } else { 1073 - column_gap 1080 + main_gap 1074 1081 }; 1075 1082 1076 1083 if !current_line.is_empty() && line_main_size + gap + item_outer > container_main_size { ··· 1079 1086 } 1080 1087 1081 1088 if !current_line.is_empty() { 1082 - line_main_size += column_gap; 1089 + line_main_size += main_gap; 1083 1090 } 1084 1091 line_main_size += item_outer; 1085 1092 current_line.push(i); ··· 1098 1105 for line in &lines { 1099 1106 // Total hypothetical main sizes + gaps. 1100 1107 let total_gaps = if line.len() > 1 { 1101 - (line.len() - 1) as f32 * column_gap 1108 + (line.len() - 1) as f32 * main_gap 1102 1109 } else { 1103 1110 0.0 1104 1111 }; ··· 1229 1236 1230 1237 // Step 6: Position items on main and cross axes. 1231 1238 let total_cross_gaps = if lines.len() > 1 { 1232 - (lines.len() - 1) as f32 * row_gap 1239 + (lines.len() - 1) as f32 * cross_gap 1233 1240 } else { 1234 1241 0.0 1235 1242 }; ··· 1254 1261 1255 1262 // Main-axis justification. 1256 1263 let total_main_gaps = if line.len() > 1 { 1257 - (line.len() - 1) as f32 * column_gap 1264 + (line.len() - 1) as f32 * main_gap 1258 1265 } else { 1259 1266 0.0 1260 1267 }; ··· 1378 1385 // Add gap between items (not after last). 1379 1386 if item_pos < line_items.len() - 1 { 1380 1387 if is_reverse { 1381 - main_cursor -= column_gap; 1388 + main_cursor -= main_gap; 1382 1389 } else { 1383 - main_cursor += column_gap; 1390 + main_cursor += main_gap; 1384 1391 } 1385 1392 } 1386 1393 ··· 1394 1401 } 1395 1402 } 1396 1403 1397 - cross_cursor += line_cross + row_gap + ac_between_offset; 1404 + cross_cursor += line_cross + cross_gap + ac_between_offset; 1398 1405 } 1399 1406 1400 1407 // Set parent height based on children. ··· 1412 1419 .map(|&i| items[i].target_main + items[i].outer_main) 1413 1420 .sum(); 1414 1421 let gaps = if line.len() > 1 { 1415 - (line.len() - 1) as f32 * column_gap 1422 + (line.len() - 1) as f32 * main_gap 1416 1423 } else { 1417 1424 0.0 1418 1425 };