(
state: &mut WebAccessibilityState,
accessibility_configs: &rustc_hash::FxHashMap<u32, crate::accessibility::AccessibilityConfig>,
accessibility_bounds: &rustc_hash::FxHashMap<u32, crate:
| 97 | |
| 98 | #[cfg(target_arch = "wasm32")] |
| 99 | pub fn sync_accessibility_tree( |
| 100 | state: &mut WebAccessibilityState, |
| 101 | accessibility_configs: &rustc_hash::FxHashMap<u32, crate::accessibility::AccessibilityConfig>, |
| 102 | accessibility_bounds: &rustc_hash::FxHashMap<u32, crate::math::BoundingBox>, |
| 103 | accessibility_element_order: &[u32], |
| 104 | focused_element_id: u32, |
| 105 | viewport: crate::math::Dimensions, |
| 106 | ) { |
| 107 | // Initialize the hidden DOM root on first call |
| 108 | if !state.initialized { |
| 109 | unsafe { ply_a11y_init(); } |
| 110 | state.initialized = true; |
| 111 | } |
| 112 | |
| 113 | unsafe { ply_a11y_set_viewport(viewport.width, viewport.height); } |
| 114 | |
| 115 | // Track which IDs exist this frame |
| 116 | let mut current_ids = FxHashSet::with_capacity_and_hasher(accessibility_configs.len(), Default::default()); |
| 117 | |
| 118 | // Iterate in layout order (not HashMap order) |
| 119 | for &elem_id in accessibility_element_order { |
| 120 | let (config, bounds) = match ( |
| 121 | accessibility_configs.get(&elem_id), |
| 122 | accessibility_bounds.get(&elem_id), |
| 123 | ) { |
| 124 | (Some(config), Some(bounds)) => (config, bounds), |
| 125 | _ => continue, |
| 126 | }; |
| 127 | current_ids.insert(elem_id); |
| 128 | |
| 129 | let role_str = role_to_aria_string(&config.role); |
| 130 | let tab_index = if config.focusable { |
| 131 | config.tab_index.unwrap_or(0) |
| 132 | } else { |
| 133 | -1 |
| 134 | }; |
| 135 | |
| 136 | unsafe { |
| 137 | ply_a11y_upsert_node( |
| 138 | elem_id, |
| 139 | role_str.as_ptr(), |
| 140 | role_str.len() as u32, |
| 141 | config.label.as_ptr(), |
| 142 | config.label.len() as u32, |
| 143 | tab_index, |
| 144 | ); |
| 145 | ply_a11y_set_bounds(elem_id, bounds.x, bounds.y, bounds.width, bounds.height); |
| 146 | } |
| 147 | |
| 148 | // Heading level |
| 149 | if let AccessibilityRole::Heading { level } = &config.role { |
| 150 | unsafe { ply_a11y_set_heading_level(elem_id, *level as u32); } |
| 151 | } |
| 152 | |
| 153 | // Checked state |
| 154 | if let Some(checked) = config.checked { |
| 155 | unsafe { ply_a11y_set_checked(elem_id, if checked { 1 } else { 0 }); } |
| 156 | } |
no test coverage detected