Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: Source/modules/speech/SpeechSynthesis.cpp

Issue 180553004: Fix use-after-free of m_currentSpeechUtterance. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix nullptr again? Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 24 matching lines...) Expand all
35 namespace WebCore { 35 namespace WebCore {
36 36
37 PassRefPtrWillBeRawPtr<SpeechSynthesis> SpeechSynthesis::create(ExecutionContext * context) 37 PassRefPtrWillBeRawPtr<SpeechSynthesis> SpeechSynthesis::create(ExecutionContext * context)
38 { 38 {
39 return adoptRefWillBeRefCountedGarbageCollected(new SpeechSynthesis(context) ); 39 return adoptRefWillBeRefCountedGarbageCollected(new SpeechSynthesis(context) );
40 } 40 }
41 41
42 SpeechSynthesis::SpeechSynthesis(ExecutionContext* context) 42 SpeechSynthesis::SpeechSynthesis(ExecutionContext* context)
43 : ContextLifecycleObserver(context) 43 : ContextLifecycleObserver(context)
44 , m_platformSpeechSynthesizer(PlatformSpeechSynthesizer::create(this)) 44 , m_platformSpeechSynthesizer(PlatformSpeechSynthesizer::create(this))
45 , m_currentSpeechUtterance(nullptr)
46 , m_isPaused(false) 45 , m_isPaused(false)
47 { 46 {
48 ScriptWrappable::init(this); 47 ScriptWrappable::init(this);
49 } 48 }
50 49
51 void SpeechSynthesis::setPlatformSynthesizer(PassOwnPtr<PlatformSpeechSynthesize r> synthesizer) 50 void SpeechSynthesis::setPlatformSynthesizer(PassOwnPtr<PlatformSpeechSynthesize r> synthesizer)
52 { 51 {
53 m_platformSpeechSynthesizer = synthesizer; 52 m_platformSpeechSynthesizer = synthesizer;
54 } 53 }
55 54
(...skipping 20 matching lines...) Expand all
76 for (size_t k = 0; k < voiceCount; k++) 75 for (size_t k = 0; k < voiceCount; k++)
77 m_voiceList.append(SpeechSynthesisVoice::create(platformVoices[k])); 76 m_voiceList.append(SpeechSynthesisVoice::create(platformVoices[k]));
78 77
79 return m_voiceList; 78 return m_voiceList;
80 } 79 }
81 80
82 bool SpeechSynthesis::speaking() const 81 bool SpeechSynthesis::speaking() const
83 { 82 {
84 // If we have a current speech utterance, then that means we're assumed to b e in a speaking state. 83 // If we have a current speech utterance, then that means we're assumed to b e in a speaking state.
85 // This state is independent of whether the utterance happens to be paused. 84 // This state is independent of whether the utterance happens to be paused.
86 return m_currentSpeechUtterance; 85 return currentSpeechUtterance();
87 } 86 }
88 87
89 bool SpeechSynthesis::pending() const 88 bool SpeechSynthesis::pending() const
90 { 89 {
91 // This is true if there are any utterances that have not started. 90 // This is true if there are any utterances that have not started.
92 // That means there will be more than one in the queue. 91 // That means there will be more than one in the queue.
93 return m_utteranceQueue.size() > 1; 92 return m_utteranceQueue.size() > 1;
94 } 93 }
95 94
96 bool SpeechSynthesis::paused() const 95 bool SpeechSynthesis::paused() const
97 { 96 {
98 return m_isPaused; 97 return m_isPaused;
99 } 98 }
100 99
101 void SpeechSynthesis::startSpeakingImmediately(SpeechSynthesisUtterance* utteran ce) 100 void SpeechSynthesis::startSpeakingImmediately()
102 { 101 {
103 ASSERT(!m_currentSpeechUtterance); 102 SpeechSynthesisUtterance* utterance = currentSpeechUtterance();
103 ASSERT(utterance);
104
104 utterance->setStartTime(monotonicallyIncreasingTime()); 105 utterance->setStartTime(monotonicallyIncreasingTime());
105 m_currentSpeechUtterance = utterance;
106 m_isPaused = false; 106 m_isPaused = false;
107 m_platformSpeechSynthesizer->speak(utterance->platformUtterance()); 107 m_platformSpeechSynthesizer->speak(utterance->platformUtterance());
108 } 108 }
109 109
110 void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance, ExceptionState& exceptionState) 110 void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance, ExceptionState& exceptionState)
111 { 111 {
112 if (!utterance) { 112 if (!utterance) {
113 exceptionState.throwTypeError("Invalid utterance argument"); 113 exceptionState.throwTypeError("Invalid utterance argument");
114 return; 114 return;
115 } 115 }
116 116
117 m_utteranceQueue.append(utterance); 117 m_utteranceQueue.append(utterance);
118 118
119 // If the queue was empty, speak this immediately and add it to the queue. 119 // If the queue was empty, speak this immediately.
120 if (m_utteranceQueue.size() == 1) 120 if (m_utteranceQueue.size() == 1)
121 startSpeakingImmediately(utterance); 121 startSpeakingImmediately();
122 } 122 }
123 123
124 void SpeechSynthesis::cancel() 124 void SpeechSynthesis::cancel()
125 { 125 {
126 // Remove all the items from the utterance queue. 126 // Remove all the items from the utterance queue. The platform
127 // Hold on to the current utterance so the platform synthesizer can have a c hance to clean up. 127 // may still have references to some of these utterances and may
128 RefPtrWillBeMember<SpeechSynthesisUtterance> current = m_currentSpeechUttera nce; 128 // fire events on them asynchronously.
129 m_utteranceQueue.clear(); 129 m_utteranceQueue.clear();
130 m_platformSpeechSynthesizer->cancel(); 130 m_platformSpeechSynthesizer->cancel();
131 current = nullptr;
132
133 // The platform should have called back immediately and cleared the current utterance.
134 ASSERT(!m_currentSpeechUtterance);
135 } 131 }
136 132
137 void SpeechSynthesis::pause() 133 void SpeechSynthesis::pause()
138 { 134 {
139 if (!m_isPaused) 135 if (!m_isPaused)
140 m_platformSpeechSynthesizer->pause(); 136 m_platformSpeechSynthesizer->pause();
141 } 137 }
142 138
143 void SpeechSynthesis::resume() 139 void SpeechSynthesis::resume()
144 { 140 {
145 if (!m_currentSpeechUtterance) 141 if (!currentSpeechUtterance())
146 return; 142 return;
147 m_platformSpeechSynthesizer->resume(); 143 m_platformSpeechSynthesizer->resume();
148 } 144 }
149 145
150 void SpeechSynthesis::fireEvent(const AtomicString& type, SpeechSynthesisUtteran ce* utterance, unsigned long charIndex, const String& name) 146 void SpeechSynthesis::fireEvent(const AtomicString& type, SpeechSynthesisUtteran ce* utterance, unsigned long charIndex, const String& name)
151 { 147 {
152 if (!executionContext()->activeDOMObjectsAreStopped()) 148 if (!executionContext()->activeDOMObjectsAreStopped())
153 utterance->dispatchEvent(SpeechSynthesisEvent::create(type, charIndex, ( currentTime() - utterance->startTime()), name)); 149 utterance->dispatchEvent(SpeechSynthesisEvent::create(type, charIndex, ( currentTime() - utterance->startTime()), name));
154 } 150 }
155 151
156 void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance* utteranc e, bool errorOccurred) 152 void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance* utteranc e, bool errorOccurred)
157 { 153 {
158 ASSERT(utterance); 154 ASSERT(utterance);
159 ASSERT(m_currentSpeechUtterance);
160 m_currentSpeechUtterance = nullptr;
161 155
156 bool didJustFinishCurrentUtterance = false;
157 // If the utterance that completed was the one we're currently speaking,
158 // remove it from the queue and start speaking the next one.
159 if (utterance == currentSpeechUtterance()) {
160 m_utteranceQueue.removeFirst();
161 didJustFinishCurrentUtterance = true;
162 }
163
164 // Always fire the event, because the platform may have asynchronously
165 // sent an event on an utterance before it got the message that we
166 // canceled it, and we should always report to the user what actually
167 // happened.
162 fireEvent(errorOccurred ? EventTypeNames::error : EventTypeNames::end, utter ance, 0, String()); 168 fireEvent(errorOccurred ? EventTypeNames::error : EventTypeNames::end, utter ance, 0, String());
163 169
164 if (m_utteranceQueue.size()) { 170 // Start the next utterance if we just finished one and one was pending.
165 RefPtrWillBeMember<SpeechSynthesisUtterance> firstUtterance = m_utteranc eQueue.first(); 171 if (didJustFinishCurrentUtterance && !m_utteranceQueue.isEmpty())
166 ASSERT(firstUtterance == utterance); 172 startSpeakingImmediately();
167 if (firstUtterance == utterance)
168 m_utteranceQueue.removeFirst();
169
170 // Start the next job if there is one pending.
171 if (!m_utteranceQueue.isEmpty())
172 startSpeakingImmediately(m_utteranceQueue.first().get());
173 }
174 } 173 }
175 174
176 void SpeechSynthesis::boundaryEventOccurred(PassRefPtr<PlatformSpeechSynthesisUt terance> utterance, SpeechBoundary boundary, unsigned charIndex) 175 void SpeechSynthesis::boundaryEventOccurred(PassRefPtr<PlatformSpeechSynthesisUt terance> utterance, SpeechBoundary boundary, unsigned charIndex)
177 { 176 {
178 DEFINE_STATIC_LOCAL(const String, wordBoundaryString, ("word")); 177 DEFINE_STATIC_LOCAL(const String, wordBoundaryString, ("word"));
179 DEFINE_STATIC_LOCAL(const String, sentenceBoundaryString, ("sentence")); 178 DEFINE_STATIC_LOCAL(const String, sentenceBoundaryString, ("sentence"));
180 179
181 switch (boundary) { 180 switch (boundary) {
182 case SpeechWordBoundary: 181 case SpeechWordBoundary:
183 fireEvent(EventTypeNames::boundary, static_cast<SpeechSynthesisUtterance *>(utterance->client()), charIndex, wordBoundaryString); 182 fireEvent(EventTypeNames::boundary, static_cast<SpeechSynthesisUtterance *>(utterance->client()), charIndex, wordBoundaryString);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 if (utterance->client()) 214 if (utterance->client())
216 handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance ->client()), false); 215 handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance ->client()), false);
217 } 216 }
218 217
219 void SpeechSynthesis::speakingErrorOccurred(PassRefPtr<PlatformSpeechSynthesisUt terance> utterance) 218 void SpeechSynthesis::speakingErrorOccurred(PassRefPtr<PlatformSpeechSynthesisUt terance> utterance)
220 { 219 {
221 if (utterance->client()) 220 if (utterance->client())
222 handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance ->client()), true); 221 handleSpeakingCompleted(static_cast<SpeechSynthesisUtterance*>(utterance ->client()), true);
223 } 222 }
224 223
224 SpeechSynthesisUtterance* SpeechSynthesis::currentSpeechUtterance() const
225 {
226 if (!m_utteranceQueue.isEmpty())
227 return m_utteranceQueue.first().get();
228 return 0;
229 }
230
225 const AtomicString& SpeechSynthesis::interfaceName() const 231 const AtomicString& SpeechSynthesis::interfaceName() const
226 { 232 {
227 return EventTargetNames::SpeechSynthesisUtterance; 233 return EventTargetNames::SpeechSynthesisUtterance;
228 } 234 }
229 235
230 void SpeechSynthesis::trace(Visitor* visitor) 236 void SpeechSynthesis::trace(Visitor* visitor)
231 { 237 {
232 visitor->trace(m_voiceList); 238 visitor->trace(m_voiceList);
233 visitor->trace(m_currentSpeechUtterance);
234 visitor->trace(m_utteranceQueue); 239 visitor->trace(m_utteranceQueue);
235 } 240 }
236 241
237 } // namespace WebCore 242 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/modules/speech/SpeechSynthesis.h ('k') | Source/modules/speech/testing/PlatformSpeechSynthesizerMock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698