window.speechSynthesis needs to be cheap
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Jun 2013 23:26:02 +0000 (23:26 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Jun 2013 23:26:02 +0000 (23:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=117111
rdar://problem/14042030

Reviewed by Dean Jackson.

Add the traditional laziness to all of the speech synthesis code, wherever
it was omitted.

* Modules/speech/SpeechSynthesis.cpp:
(WebCore::SpeechSynthesis::create): Tweaked style (took out unneeded parentheses).
(WebCore::SpeechSynthesis::SpeechSynthesis): Don't create m_platformSpeechSynthesizer.
(WebCore::SpeechSynthesis::setPlatformSynthesizer): Clear state when changing the
platform speech synthesizer. Since this code is only used to set up a mock in the
test runner, the fact that it was wrong before was harmless, but still not good.
(WebCore::SpeechSynthesis::getVoices): Create the platform speech synthesizer here
so we can get the voice list from it.
(WebCore::SpeechSynthesis::startSpeakingImmediately): Create the platform speech
synthesizer here.
(WebCore::SpeechSynthesis::cancel): Check the platform speech synthesizer for
null and do nothing if it's not present.
(WebCore::SpeechSynthesis::pause): Ditto.
(WebCore::SpeechSynthesis::resume): Ditto.

* platform/PlatformSpeechSynthesizer.cpp:
(WebCore::PlatformSpeechSynthesizer::create): Don't call initializeVoiceList just
to create a synthesizer.
(WebCore::PlatformSpeechSynthesizer::voiceList): Do call initializeVoiceList once
when asked for a voice list.

* platform/PlatformSpeechSynthesizer.h: The voiceList function is no longer inlined.
The unused setVoiceList function has been removed. The initializeVoiceList is now
private rather than protected. Added a new m_voiceListIsInitialized boolean.

* platform/mac/PlatformSpeechSynthesizerMac.mm:
(WebCore::PlatformSpeechSynthesizer::PlatformSpeechSynthesizer): Initialize
m_voiceListIsInitialized to false.

* platform/mock/PlatformSpeechSynthesizerMock.cpp:
(WebCore::PlatformSpeechSynthesizerMock::create): Don't call initializeVoiceList just
to create a synthesizer.
(WebCore::PlatformSpeechSynthesizerMock::~PlatformSpeechSynthesizerMock):
Removed unneeded call to m_speakingFinishedTimer.stop() since timers automatically
stop when you destroy them.
(WebCore::PlatformSpeechSynthesizerMock::initializeVoiceList): Removed unneeded
call to m_voiceList.clear(), since the caller only calls this once when the
voice list is already clear.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@151076 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/Modules/speech/SpeechSynthesis.cpp
Source/WebCore/platform/PlatformSpeechSynthesizer.cpp
Source/WebCore/platform/PlatformSpeechSynthesizer.h
Source/WebCore/platform/mac/PlatformSpeechSynthesizerMac.mm
Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp

index db54b7d..f39cc60 100644 (file)
@@ -1,3 +1,53 @@
+2013-06-01  Darin Adler  <darin@apple.com>
+
+        window.speechSynthesis needs to be cheap
+        https://bugs.webkit.org/show_bug.cgi?id=117111
+        rdar://problem/14042030
+
+        Reviewed by Dean Jackson.
+
+        Add the traditional laziness to all of the speech synthesis code, wherever
+        it was omitted.
+
+        * Modules/speech/SpeechSynthesis.cpp:
+        (WebCore::SpeechSynthesis::create): Tweaked style (took out unneeded parentheses).
+        (WebCore::SpeechSynthesis::SpeechSynthesis): Don't create m_platformSpeechSynthesizer.
+        (WebCore::SpeechSynthesis::setPlatformSynthesizer): Clear state when changing the
+        platform speech synthesizer. Since this code is only used to set up a mock in the
+        test runner, the fact that it was wrong before was harmless, but still not good.
+        (WebCore::SpeechSynthesis::getVoices): Create the platform speech synthesizer here
+        so we can get the voice list from it.
+        (WebCore::SpeechSynthesis::startSpeakingImmediately): Create the platform speech
+        synthesizer here.
+        (WebCore::SpeechSynthesis::cancel): Check the platform speech synthesizer for
+        null and do nothing if it's not present.
+        (WebCore::SpeechSynthesis::pause): Ditto.
+        (WebCore::SpeechSynthesis::resume): Ditto.
+
+        * platform/PlatformSpeechSynthesizer.cpp:
+        (WebCore::PlatformSpeechSynthesizer::create): Don't call initializeVoiceList just
+        to create a synthesizer.
+        (WebCore::PlatformSpeechSynthesizer::voiceList): Do call initializeVoiceList once
+        when asked for a voice list.
+
+        * platform/PlatformSpeechSynthesizer.h: The voiceList function is no longer inlined.
+        The unused setVoiceList function has been removed. The initializeVoiceList is now
+        private rather than protected. Added a new m_voiceListIsInitialized boolean.
+
+        * platform/mac/PlatformSpeechSynthesizerMac.mm:
+        (WebCore::PlatformSpeechSynthesizer::PlatformSpeechSynthesizer): Initialize
+        m_voiceListIsInitialized to false.
+
+        * platform/mock/PlatformSpeechSynthesizerMock.cpp:
+        (WebCore::PlatformSpeechSynthesizerMock::create): Don't call initializeVoiceList just
+        to create a synthesizer.
+        (WebCore::PlatformSpeechSynthesizerMock::~PlatformSpeechSynthesizerMock):
+        Removed unneeded call to m_speakingFinishedTimer.stop() since timers automatically
+        stop when you destroy them.
+        (WebCore::PlatformSpeechSynthesizerMock::initializeVoiceList): Removed unneeded
+        call to m_voiceList.clear(), since the caller only calls this once when the
+        voice list is already clear.
+
 2013-06-01  Andreas Kling  <akling@apple.com>
 
         Fix typo in r151071.
index 1d2b58d..bad82da 100644 (file)
@@ -38,12 +38,11 @@ namespace WebCore {
     
 PassRefPtr<SpeechSynthesis> SpeechSynthesis::create()
 {
-    return adoptRef(new SpeechSynthesis());
+    return adoptRef(new SpeechSynthesis);
 }
     
 SpeechSynthesis::SpeechSynthesis()
-    : m_platformSpeechSynthesizer(PlatformSpeechSynthesizer::create(this))
-    , m_currentSpeechUtterance(0)
+    : m_currentSpeechUtterance(0)
     , m_isPaused(false)
 {
 }
@@ -51,6 +50,10 @@ SpeechSynthesis::SpeechSynthesis()
 void SpeechSynthesis::setPlatformSynthesizer(PassOwnPtr<PlatformSpeechSynthesizer> synthesizer)
 {
     m_platformSpeechSynthesizer = synthesizer;
+    m_voiceList.clear();
+    m_currentSpeechUtterance = 0;
+    m_utteranceQueue.clear();
+    m_isPaused = false;
 }
     
 void SpeechSynthesis::voicesDidChange()
@@ -62,7 +65,10 @@ const Vector<RefPtr<SpeechSynthesisVoice> >& SpeechSynthesis::getVoices()
 {
     if (m_voiceList.size())
         return m_voiceList;
-    
+
+    if (!m_platformSpeechSynthesizer)
+        m_platformSpeechSynthesizer = PlatformSpeechSynthesizer::create(this);
+
     // If the voiceList is empty, that's the cue to get the voices from the platform again.
     const Vector<RefPtr<PlatformSpeechSynthesisVoice> >& platformVoices = m_platformSpeechSynthesizer->voiceList();
     size_t voiceCount = platformVoices.size();
@@ -97,6 +103,8 @@ void SpeechSynthesis::startSpeakingImmediately(SpeechSynthesisUtterance* utteran
     utterance->setStartTime(monotonicallyIncreasingTime());
     m_currentSpeechUtterance = utterance;
     m_isPaused = false;
+    if (!m_platformSpeechSynthesizer)
+        m_platformSpeechSynthesizer = PlatformSpeechSynthesizer::create(this);
     m_platformSpeechSynthesizer->speak(utterance->platformUtterance());
 }
 
@@ -118,7 +126,8 @@ void SpeechSynthesis::cancel()
     // Hold on to the current utterance so the platform synthesizer can have a chance to clean up.
     RefPtr<SpeechSynthesisUtterance> current = m_currentSpeechUtterance;
     m_utteranceQueue.clear();
-    m_platformSpeechSynthesizer->cancel();
+    if (m_platformSpeechSynthesizer)
+        m_platformSpeechSynthesizer->cancel();
     current = 0;
     
     // The platform should have called back immediately and cleared the current utterance.
@@ -127,15 +136,14 @@ void SpeechSynthesis::cancel()
 
 void SpeechSynthesis::pause()
 {
-    if (!m_isPaused)
+    if (!m_isPaused && m_platformSpeechSynthesizer)
         m_platformSpeechSynthesizer->pause();
 }
 
 void SpeechSynthesis::resume()
 {
-    if (!m_currentSpeechUtterance)
-        return;
-    m_platformSpeechSynthesizer->resume();
+    if (m_currentSpeechUtterance && m_platformSpeechSynthesizer)
+        m_platformSpeechSynthesizer->resume();
 }
 
 void SpeechSynthesis::fireEvent(const AtomicString& type, SpeechSynthesisUtterance* utterance, unsigned long charIndex, const String& name)
index f98e142..f23687a 100644 (file)
@@ -32,17 +32,19 @@ namespace WebCore {
     
 PassOwnPtr<PlatformSpeechSynthesizer> PlatformSpeechSynthesizer::create(PlatformSpeechSynthesizerClient* client)
 {
-    OwnPtr<PlatformSpeechSynthesizer> synthesizer = adoptPtr(new PlatformSpeechSynthesizer(client));
-    synthesizer->initializeVoiceList();
-    return synthesizer.release();
+    return adoptPtr(new PlatformSpeechSynthesizer(client));
 }
 
-void PlatformSpeechSynthesizer::setVoiceList(Vector<RefPtr<PlatformSpeechSynthesisVoice> >& voices)
+const Vector<RefPtr<PlatformSpeechSynthesisVoice> >& PlatformSpeechSynthesizer::voiceList() const
 {
-    m_voiceList = voices;
+    if (!m_voiceListIsInitialized) {
+        ASSERT(m_voiceList.isEmpty());
+        const_cast<PlatformSpeechSynthesizer*>(this)->initializeVoiceList();
+        const_cast<PlatformSpeechSynthesizer*>(this)->m_voiceListIsInitialized = true;
+    }
+    return m_voiceList;
 }
 
-
 } // namespace WebCore
 
 #endif // ENABLE(SPEECH_SYNTHESIS)
index d21b84b..b223cfc 100644 (file)
@@ -58,14 +58,16 @@ public:
 protected:
     virtual ~PlatformSpeechSynthesizerClient() { }
 };
-    
+
 class PlatformSpeechSynthesizer {
 public:
     static PassOwnPtr<PlatformSpeechSynthesizer> create(PlatformSpeechSynthesizerClient*);
 
+    // FIXME: We have multiple virtual functions just so we can support a mock for testing.
+    // Seems wasteful. Would be nice to find a better way.
     virtual ~PlatformSpeechSynthesizer();
     
-    const Vector<RefPtr<PlatformSpeechSynthesisVoice> >& voiceList() const { return m_voiceList; }
+    const Vector<RefPtr<PlatformSpeechSynthesisVoice> >& voiceList() const;
     virtual void speak(PassRefPtr<PlatformSpeechSynthesisUtterance>);
     virtual void pause();
     virtual void resume();
@@ -73,14 +75,15 @@ public:
     
     PlatformSpeechSynthesizerClient* client() const { return m_speechSynthesizerClient; }
 
-    void setVoiceList(Vector<RefPtr<PlatformSpeechSynthesisVoice> >&);
-
 protected:
-    virtual void initializeVoiceList();
     explicit PlatformSpeechSynthesizer(PlatformSpeechSynthesizerClient*);
+
     Vector<RefPtr<PlatformSpeechSynthesisVoice> > m_voiceList;
-    
+
 private:
+    virtual void initializeVoiceList();
+
+    bool m_voiceListIsInitialized;
     PlatformSpeechSynthesizerClient* m_speechSynthesizerClient;
     
 #if PLATFORM(MAC)
index fd71cbb..fb30bbe 100644 (file)
 namespace WebCore {
 
 PlatformSpeechSynthesizer::PlatformSpeechSynthesizer(PlatformSpeechSynthesizerClient* client)
-    : m_speechSynthesizerClient(client)
+    : m_voiceListIsInitialized(false)
+    , m_speechSynthesizerClient(client)
 {
 }
 
index e94195a..ca75766 100644 (file)
@@ -33,9 +33,7 @@ namespace WebCore {
 
 PassOwnPtr<PlatformSpeechSynthesizerMock> PlatformSpeechSynthesizerMock::create(PlatformSpeechSynthesizerClient* client)
 {
-    OwnPtr<PlatformSpeechSynthesizerMock> synthesizer = adoptPtr(new PlatformSpeechSynthesizerMock(client));
-    synthesizer->initializeVoiceList();
-    return synthesizer.release();
+    return adoptPtr(new PlatformSpeechSynthesizerMock(client));
 }
     
 PlatformSpeechSynthesizerMock::PlatformSpeechSynthesizerMock(PlatformSpeechSynthesizerClient* client)
@@ -46,7 +44,6 @@ PlatformSpeechSynthesizerMock::PlatformSpeechSynthesizerMock(PlatformSpeechSynth
     
 PlatformSpeechSynthesizerMock::~PlatformSpeechSynthesizerMock()
 {
-    m_speakingFinishedTimer.stop();
 }
 
 void PlatformSpeechSynthesizerMock::speakingFinished(Timer<PlatformSpeechSynthesizerMock>*)
@@ -58,7 +55,6 @@ void PlatformSpeechSynthesizerMock::speakingFinished(Timer<PlatformSpeechSynthes
     
 void PlatformSpeechSynthesizerMock::initializeVoiceList()
 {
-    m_voiceList.clear();
     m_voiceList.append(PlatformSpeechSynthesisVoice::create(String("mock.voice.bruce"), String("bruce"), String("en-US"), true, true));
     m_voiceList.append(PlatformSpeechSynthesisVoice::create(String("mock.voice.clark"), String("clark"), String("en-US"), true, false));
     m_voiceList.append(PlatformSpeechSynthesisVoice::create(String("mock.voice.logan"), String("logan"), String("fr-CA"), true, true));
@@ -98,7 +94,6 @@ void PlatformSpeechSynthesizerMock::resume()
     client()->didResumeSpeaking(m_utterance);
 }
 
-    
 } // namespace WebCore
 
 #endif // ENABLE(SPEECH_SYNTHESIS)