@@ -162,17 +162,24 @@ void SpeechSynthesis::cancel()
162162 // Remove all the items from the utterance queue.
163163 // Hold on to the current utterance so the platform synthesizer can have a chance to clean up.
164164 RefPtr<SpeechSynthesisUtterance> current = m_currentSpeechUtterance;
165- m_utteranceQueue.clear ();
165+ // Clear m_utteranceQueue before calling cancel to avoid picking up new utterances
166+ // on completion callback
167+ auto utteranceQueue = WTFMove (m_utteranceQueue);
166168 if (m_speechSynthesisClient) {
167169 m_speechSynthesisClient->cancel ();
168170 // If we wait for cancel to callback speakingErrorOccurred, then m_currentSpeechUtterance will be null
169171 // and the event won't be processed. Instead we process the error immediately.
170172 speakingErrorOccurred (SpeechSynthesisErrorCode::Canceled);
171173 m_currentSpeechUtterance = nullptr ;
172- } else if (m_platformSpeechSynthesizer) {
174+ } else if (m_platformSpeechSynthesizer)
173175 m_platformSpeechSynthesizer->cancel ();
174- // The platform should have called back immediately and cleared the current utterance.
175- ASSERT (!m_currentSpeechUtterance);
176+
177+ // Trigger canceled events for queued utterances
178+ while (!utteranceQueue.isEmpty ()) {
179+ const auto utterance = utteranceQueue.takeFirst ();
180+ // Current utterance is handled in platform cancel()
181+ if (current.get () != utterance.ptr ())
182+ utterance.get ().errorEventOccurred (eventNames ().errorEvent , SpeechSynthesisErrorCode::Canceled);
176183 }
177184 current = nullptr ;
178185}
0 commit comments